home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Experimental BBS Explossion 3
/
Experimental BBS Explossion III.iso
/
gus
/
gusdk210.zip
/
ULTRADOC.TXT
< prev
Wrap
Text File
|
1993-12-17
|
256KB
|
7,128 lines
UltraSound Software Development Kit (SDK)
Revision 2.10
December 24th, 1993
Documentation
by
Kurt Kennett
and
Mike Travers
Advanced Gravis
101-3750 North Fraser Way
Burnaby, British Columbia V5J 5E9
FAX (604)-431-5155
Forte Technologies
1555 East Henrietta Rd.
Rochester, N.Y. 14526
FAX (716)-292-6353
NOTICE
The information contained in this manual is believed to be correct. The
manual is subject to change without notice and does not represent a
commitment on the part of FORTE, Advanced Gravis, or Ingenuity Software.
Neither FORTE, Advanced Gravis, nor Ingenuity Software make a warranty of
any kind with regard to this material, including, but not limited to, the
implied warranties of merchantability and fitness for a particular purpose.
Neither FORTE, Advanced Gravis, nor Ingenuity Software shall be liable for
errors contained herein or for incidental or consequential damages in
connection with the furnishing, performance or use of this material.
This document contains proprietary information which is protected by
copyright. This manual is Copyright (C) 1992,1993 by FORTE, Advanced
Gravis, and Ingenuity Software. All rights are reserved. No part of this
document may be reproduced, transmitted, transcribed, stored in a retrieval
system, or translated into any human or computer language, in any form or
by any means; electronic, mechanical, magnetic, optical, chemical, manual
or otherwise, without the expressed written permission of FORTE, Advanced
Gravis, and Ingenuity Software.
Any copying, duplication, selling, or otherwise distributing the program or
support files described in this manual, other than for the limited purposes
of system backup and loading the program into the computer as part of
executing the program, is a violation of the software license agreement and
the law. Willful violation of the copyright law of the United States can
result in statutory damages of up to $50,000 in addition to actual damages,
plus criminal penalties of imprisonment for up to one year and/or a
$10,000 fine.
TABLE OF CONTENTS
Section Page
Chapter 1 - General Information 3
1.0 Introduction 3
1.1 Features of the UltraSound 3
1.2 Benefits of supporting the UltraSound 4
1.3 The GF1 - 32 Voice Sound Synthesizer 4
1.4 MIDI Interface 7
1.5 Joystick Interface 7
Chapter 2 - Hardware Information 8
2.1 I/O Port Map 8
2.2 MIDI Control Port 9
2.3 MIDI Status Port 9
2.4 MIDI Data Port 9
2.5 Page Register 10
2.6 Select Register 10
2.6.1 Global Registers 10
2.6.1.1 DRAM DMA Control Register 11
2.6.1.2 DMA Start Address 11
2.6.1.3 DRAM I/O Address 12
2.6.1.4 Timer Control 12
2.6.1.5 Timer 1 and Timer 2 Count 12
2.6.1.6 Sampling Frequency 12
2.6.1.7 Sampling Control Register 13
2.6.1.8 Joystick Trim DAC 13
2.6.1.9 Reset Register 14
2.6.2 Voice-specific Registers 14
2.6.2.1 Voice Control Register 15
2.6.2.2 Frequency Control Register 16
2.6.2.3 Starting location HIGH 16
2.6.2.4 Starting location LOW 16
2.6.2.5 End Address HIGH 16
2.6.2.6 End Address LOW 16
2.6.2.7 Volume Ramp Rate 17
2.6.2.8 Volume Ramp Start 17
2.6.2.9 Volume Ramp End 17
2.6.2.10 Current Volume 18
2.6.2.11 Current Location HIGH 18
2.6.2.12 Current Location LOW 18
2.6.2.13 Pan Position 18
2.6.2.14 Volume Ramp Control Register 19
2.6.2.15 Active Voices 19
2.6.2.16 IRQ Source Register 20
2.7 Global Data Low 20
2.8 Global Data High 20
2.9 IRQ Status 21
2.10 Timer Control Register 21
2.11 Timer Data Register 21
2.12 DRAM I/O 21
Section Page
2.13 Mix Control Register 22
2.14 IRQ Control Register 22
2.15 Register Control 24
2.16 Volume ramping description 24
Chapter 3 - Programming the UltraSound 26
3.0 Introduction 26
3.1 Sound 26
3.2 The Basics of the UltraSound 27
3.3 Using GUS Memory 27
3.4 What are Samples? 28
3.5 Using Voices 29
3.6 Volumes 30
3.7 Using Looping 30
3.8 Clicks and click removal 31
3.9 Interrupt Handling Functions 32
3.10 Rollover feature 32
3.11 Stereo playback 33
3.12 C-specific information 35
3.13 PASCAL-specific information 36
3.13.1 Available constants and variables 37
3.13.2 Examples 39
3.13.3 Management of GUS RAM 40
3.14 Coming Attractions 41
3.15 Technical Support 42
Chapter 4 - Reference Guide 43
UltraAllocVoice 81
UltraAuxHandler 54
UltraCalcRate 43
UltraClearVoices 81
UltraClose 43
UltraDisableLineIn 46
UltraDisableMicIn 46
UltraDisableMIDIXmit 58
UltraDisableOutput 47
UltraDownload 44
UltraDRAMDMABusy 45
UltraDRAMTcHandler 50
UltraEnableLineIn 47
UltraEnableMicIn 47
UltraEnableMIDIXmit 59
UltraEnableOutput 48
UltraFreeVoice 82
UltraGetLineIn 48
UltraGetMicIn 49
UltraGetOutput 48
UltraGoRecord 45
UltraGoVoice 46
UltraMaxAlloc 55
UltraMaxAvail 55
Section Page
UltraMemAlloc 56
UltraMemAvail 56
UltraMemFree 57
UltraMemInit 57
UltraMIDIDisableRecv 58
UltraMIDIEnableRecv 58
UltraMIDIRecv 59
UltraMIDIRecvHandler 51
UltraMIDIReset 60
UltraMIDIStatus 60
UltraMIDIXmit 60
UltraMIDIXmitHandler 51
UltraOpen 61
UltraPeekData 62
UltraPing 62
UltraPokeData 63
UltraPrimeRecord 64
UltraPrimeVoice 65
UltraProbe 66
UltraRampLinearVolume 84
UltraRampVolume 67
UltraReadLinearVolume 84
UltraReadRecordPosition 67
UltraReadVoice 68
UltraReadVolume 68
UltraRecordData 69
UltraRecordDMABusy 70
UltraRecordHandler 54
UltraReset 70
UltraSetBalance 71
UltraSetFrequency 71
UltraSetLinearVolume 83
UltraSetLoopMode 71
UltraSetRecordFrequency 72
UltraSetVoice 72
UltraSetVoiceEnd 72
UltraSetVolume 73
UltraSizeDRAM 73
UltraStartTimer 74
UltraStartVoice 75
UltraStopTimer 75
UltraStopVoice 76
UltraStopVolume 76
UltraTimer1Handler 52
UltraTimer2Handler 52
UltraTimerStopped 76
UltraTrimJoystick 77
UltraUpload 77
UltraVectorLinearVolume 85
UltraVectorVolume 78
UltraVersion 78
UltraVersionStr 79
Section Page
UltraVoiceOff 82
UltraVoiceOn 83
UltraVoiceStopped 79
UltraVolumeHandler 53
UltraVolumeStopped 79
UltraWaitDRAMDMA 80
UltraWaitRecordDMA 80
UltraWaveHandler 53
Chapter 5 - Focal Point 3D Sound 86
5.0 Introduction 86
5.1 Creating 3D file 87
5.2 3D Sound Routines 87
UltraAbsPosition 87
UltraAngPosition3D 88
UltraAngFltPosition3D 89
UltraCloseDup3D 89
UltrDup3D 90
UltraLoad3DEffect 91
UltraSetFreq3D 92
UltraRelease3DInterleave 92
UltraSetup3DInterleave 93
UltraStart3D 93
UltraStop3D 94
UltraUnLoad3DEffect 94
Appendix A - Error Codes 95
Appendix B - Volume Control 96
Appendix C - Voice Control 97
Appendix D - DMA Control 98
Appendix E - Recording Control 99
Appendix F - Patch Files 100
Field descriptions 104
Appendix G - 3D File Header 109
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Chapter 1 - General Information
1.0 Introduction
This is version 2.10 of the Software Development Kit (SDK) for the Advanced
Gravis UltraSound card, and is the combined work of Advanced Gravis, FORTE
Technologies, and Ingenuity Software. This kit is intended for use by
programmers of IBM-compatible PCs. After becoming familiar with this
material, you should be able to use C or Pascal to program the UltraSound
under MS-DOS.
This is the first version which includes a full Borland Pascal (version 7)
and Turbo-Pascal (versions 6 and 7) interface. This was written by Kurt
Kennett of Ingenuity Software for Advanced Gravis, and is the direct
translation of the routines in the C interface. For specific information
about the Pascal interface, see section 3.13.
For specific information about the revised and updated C interface,
including compilers and memory models supported, see section 3.12.
Some of the discussions of the hardware interface to the card (Chapter 2)
are quite technical, and go beyond the level of technical sophistication
needed to write software. Therefore, a seperate section (Chapter 3) has
been included which is a general overview of how to write software for the
card. What follows in this chapter is a general description of the
UltraSound card and its features, the MIDI functionality, the Joystick
interface, and the GF1 32-voice Sound Synthesizer. Throughout this
documentation, the words 'lowlevel toolkit', 'lowlevel routines' and
'lowlevel code' are used. This refers to any and all of the routines
described and included in the C and/or Pascal interfaces.
1.1 Features of the UltraSound
- Jumper selectable base port address.
- Software selectable IRQ vectors and DMA channels.
- XT and AT compatibility.
- 8 or 16 bit playback: Stereo and Monophonic.
- 8 bit recording: Stereo or Monophonic.
- Playback and recording rates up to 44.1 kHz.
- 32 voice wavetable synthesis: all voices mixed on board.
- Simultaneous playback and recording is possible.
- Each voice has its own volume settings, volume enveloping, playback rate
and balance.
- Both line level and amplified outputs.
- 6850 compatible MIDI UART on-board.
- Gravis Eliminator joystick interface with jumper enable/disable.
- 256Kb DRAM on board for waveforms. Expandable to 1Mb.
- Stereo microphone input with automatic level control.
- Line level input.
- CD ROM Drive audio input.
- Stereo mini-jacks for line & amplified outputs and Mic and Line inputs.
___________________________________________________________________________
3
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
1.2 Benefits of supporting the UltraSound
The UltraSound has 32 separate voices, each of which can be used to play
back any 8- or 16-bit digital data that is loaded into its DRAM. This data
can consist of individual sound effects, a whole sound track, or even
single musical notes of a digitized instrument. The UltraSound is
completely controlled by the PC, thus giving maximum flexibility to
applications which use it. The main chip which runs the card (the GF1) is
directly addressable from the PC's CPU via basic I/O instructions.
Here are some of the features that the UltraSound offers:
1) Wavetable synthesis has a much higher sound quality that FM-based cards
can ever achieve. This method of audio synthesis is the same method
used in expensive professional keyboards.
2) 32 digital voices can be independently controlled. This allows you to
have up to 32 sound effects or instruments going at once.
3) The card is RAM-based. Since the instrument patches are kept on disk
and only loaded when they are needed, they can be changed or improved
at will.
4) Focal Point 3D sound generation. You can position your applications
sounds anywhere in 3D space around the listener.
5) All mixing is done on the card. There is no burden on the CPU to
playback multiple channels.
6) Multiple cards can be installed in the same PC. With some relatively
minor adjustments to the SDK software, multiple cards can be controlled
in the same PC.
7) Hardware-assisted voice enveloping. A multi-point attack-decay-sustain-
release envelope can be implemented that uses virtually no CPU
overhead. Tremelo can also be done in hardware.
8) Sound effects can be pre-loaded into DRAM, using little or no PC memory
to keep track of them. This leaves more space for your application and
it's data. It also allows you to start or stop any sound whenever you
wish.
1.3 The GF1 - 32 Voice Sound Synthesizer
The UltraSound uses Wave-Table Synthesis to produce sound output. This
means that either sampled data from actual instruments or other synthesized
digital audio is stored in DRAM on the UltraSound Board. The GF1 chip
which controls the board is set up to play back relatively short digital
audio samples and produce continuous sound closely reproducing the original
instrument. The 32 voices are independently controlled and can be
producing different sounds concurently. Output from all voices is mixed
into the left or right channels. Circuitry in the GF1 can be programmed to
perform the following audio processing functions independently for each
voice:
- Frequency Shifting to produce different notes of the same instrument.
___________________________________________________________________________
4
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
- Amplitude Modulation to produce note enveloping (attack, decay, sustain,
release), overall volume control or special effects such as LFO (low
frequency amplitude modulation).
- Panning the voice from left to right channel outputs.
Multi-track digital audio recordings can be played through the GF1 by using
one voice per digital audio track. The GF1 is compatible with 8 and 16 bit
data, stereo or mono, signed or unsigned data, and 8 or 16 bit DMA
channels.
The GF1 is basically a pipeline processor. It constantly loops from voice
#0 to the end of the active voices (how to define the number of active
voices is shown later). Every 1.6 microseconds, the GF1 performs a series
of operations on a particular voice. The more active voices there are, the
longer it takes between each time a particular voice is serviced. This
puts a limit on the rate at which playback can occur. 14 active voices
will allow a maximum of 44.1 kHz playback. 28 voices will allow 22 kHz.
Faster rates can be achieved by making the frequency constant greater than
1. This will cause the GF1 to skip some data bytes to play a sample back
at the requested frequency. This is not generally a problem, but could
cause some distortion or aliasing.
The formula for calculating the playback rate is:
Frequency Active Voices
44100 14
41160 15
38587 16
36317 17
34300 18
32494 19
30870 20
29400 21
28063 22
26843 23
25725 24
24696 25
23746 26
22866 27
22050 28
21289 29
20580 30
19916 31
19293 32
This table is calculated by knowing that 14 active voices will give exactly
44.1 kHz playback. Therefore, the voice servicing rate 'X' can be
calculated from:
1,000,000 / (X * 14) = 44100 Hz
X = 1.619695497 microseconds
___________________________________________________________________________
5
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Once X is known, the frequency 'divisor' is calculated by:
divisor = 1,000,000 / (1.619695497 * # of active voices)
The lowlevel code pre-calculates this table so that floating point
arithmetic doesn't need to be done. A frequency 'counter' is used to
calculate how often a voice is updated by the GF1. To calculate an FC
(frequency counter) for any given frequency with a particular # of active
voices, run it through this formula:
C:
fc = (unsigned int)(((speed_khz<<9L)+(divisor>>1L)) / divisor);
fc = fc << 1;
PASCAL:
fc := Word(((Speed_Khz SHL 9)+(Divisor SHR 1)) DIV Divisor);
fc := fc SHL 1;
The left shift is needed since the FC is in bits 15-1. For more
information about the frequency counter, see chapter 2, the hardware
section.
This value is then put in the frequency control register for that
particular voice. If the mantissa portion of the FC is 1, then each time
around the loop, the GF1 uses each data point to play. If there is a
fractional portion, the GF1 interpolates the actual data to play from the
two data points that it is between. This makes the sound much 'smoother',
since the GF1 will create points in between the actual data points. For
example, assume an 8 bit recording at 22 kHz and 14 active voices . The
frequency control register is set up to 1/2 (exponent = 256). This means
that every time around the loop, that particular voice's accumulator is
adjusted by 1/2. So the first time the accumulator is 0 and data point 0
is used. The second time around the loop, the accumulator is 0.5. Since
there obviously is no DRAM location 0.5, the GF1 interpolates what the data
would be by looking at location 0 and location 1 and taking the appropriate
ratio from each. In this case, it picks a point half-way between the two.
If the recording rate were 11kHz, it would take 25% from location 0 and 75%
from location 1 the first time through the loop. The next time it would
take 50% from each. The next time it would take 25% from location 0 and
75% from location 1. The fourth time through it uses 100% of location 1.
The interpolation is done to a resolution of 16 bits, even for 8 bit
playback. This has the effect of making an 8 bit recording sound better
when played back on the GF1 than on a standard 8 bit card.
Remember that the GF1 works on a voice every 1.6 microseconds. This means
that the fewer voices, the faster each voice gets updated. The frequency
control register setting for the voice MUST take this into account. The FC
must get smaller if the number of active voices gets smaller. This will
increase the number of points created between the actual data points so the
perceived playback speed remains the same.
___________________________________________________________________________
6
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
1.4 MIDI Interface
The MIDI 101 interface consists of standard UART functionality - Motorola
MC68C50. An interrupt to the PC can be generated for each byte of MIDI
data received or transmitted. This hardware is independent of any of the
other hardware. The main MIDI circuitry is included in the GF1 processor,
but external to the chip is an optical isolator that is used on the serial
input data and an open collector driver that is used for the serial output.
In addition, external logic is included on board to loop back transmit data
to the receive data under software control. The serial interface has a
fixed configuration with no programmable options, as in the MC6850. A
control register is used to enable and disable the interrupt generation
logic. A status register is used to determine if the transmit or receive
register is interrupting. A read or write to the data register clears the
interrupt status.
The specifications for the interface are:
31.25 kHz +- 1%
asynchronous
1 start bit
8 data bits
1 stop bit
The MIDI signals are available on the 15 pin D connector used for the
joystick. An external cable assembly containing the optical isolator and
driver is required to use the MIDI interface.
1.5 Joystick Interface
The joystick interface is an Eliminator Joystick interface designed by
Advanced Gravis. It basically consists of a single eight bit register.
When written to, four flip-flops are reset and comparator inputs (LM339)
begin to charge up based on the position of the joystick. The comparator
threshold is setup in the GF1. Crossing the threshold of the comparators
cause the flip-flops to be preset and the capacitor to be discharged.
Reads of the register return the state of four digital inputs (internally
pulled up) and the state of the flip-flops. The rate of discharge of the
capacitors has a minimum time constant of 1 microsecond.
UltraSound boards with a revision version (printed on the card) of 3.3 and
lower have a jumper which is used to enable or disable the joystick.
Boards with a revision version of 3.4 and above have a software
enable/disable for the joystick instead of a jumper. There is a joystick
SDK available sperately from Gravis.
___________________________________________________________________________
7
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Chapter 2 - Hardware Information
2.1 I/O Port Map
The following describes I/O address map used on the board. The 'X' is
defined by the jumper settings on the UltraSound and should match that
specified in the ULTRASND environment variable.
INTERFACE I/O,MEM, R,W ADDRESS
INT,DMA HEX
------------------------------------------------------------
UltraSound Base Port: --- -- 2X0
MIDI Interface:
Control I/O W 3X0
Status I/O R 3X0
Transmit Data I/O W 3X1
Receive Data I/O R 3X1
Joystick Interface:
Trigger Timer I/O W 201
Read Data I/O R 201
GF1 Synthesizer:
GF1 Page Register I/O R/W 3X2
GF1/Global Register Select I/O R/W 3X3
GF1/Global Data Low Byte I/O R,W 3X4
GF1/Global Data High Byte I/O R/W 3X5
IRQ Status Register 1=ACTIVE I/O R 2X6
Timer Control Reg I/O R/W 2X8
Timer Data I/O W 2X9
DRAM I/O R,W 3X7
DRAM DMA R,W 1,3,5,6,7
Record Digital Audio DMA R 1,3,5,6,7
BOARD ONLY
Mix Control register I/O W 2X0
IRQ control register I/O W 2XB
(2X0- bit 6 = 1)
DMA control register I/O W 2XB
(2X0- bit 6 = 0)
Register Controls I/O R/W 2XF (Rev 3.4+)
Mixer Control I/O W 3X6 (Rev 3.7+)
At power-up the board has operational Joystick and MIDI interfaces. This
allows their direct use with existing software. The GF1 ASIC powers up with
all voices disabled, not requiring a software initialization. This helps
eliminate noise at powerup and allows the Joystick and MIDI interfaces to
be used by existing applications. The IRQ control register MUST be set up
before the MIDI interface can generate an IRQ. This is done in
ULTRINIT.EXE and when an application sets up the latches to the ULTRASND
parameters.
___________________________________________________________________________
8
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.2 MIDI Control Port - 3X0
Here are the bit definitions for the MIDI control byte. It is located at
address 3X0 hex and is write only.
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- 1 \ Master reset (when set)
| | | | | | +-------- 1 /
| | | | | +------------ Reserved
| | | | +---------------- Reserved
| | | +-------------------- Reserved
| | +------------------------ 1 \ xmit IRQ enabled
| +---------------------------- 0 /
+-------------------------------- 1 = Receive IRQ enabled
Bit 0 & 1 will cause a master reset when toggled high and then low. They
must be left low when using port. This will normally cause a transmit
buffer empty IRQ.
2.3 MIDI Status Port - 3X0
Here are the bit definitions for the MIDI status byte. It is located at
address 3X0 hex and is read-only.
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Receive reg. full
| | | | | | +-------- Transmit reg. empty
| | | | | +------------ Reserved
| | | | +---------------- Reserved
| | | +-------------------- Framing Error
| | +------------------------ Overrun error
| +---------------------------- Reserved
+-------------------------------- Interrupt pending
The MIDI control interface behaves identically to a 6850 UART.
2.4 MIDI Data Port - 3X1
The transmit and receive registers are at 3X1 hex and are 8 bits wide.
___________________________________________________________________________
9
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.5 Page Register - 3X2
This could also be called the voice select register. This register is used
to specify which voice's registers you want to read/write. This value can
range from 0 to the number of active voices specified (13-31). Once this
has been specified, you may select the specific register within that voice.
Be careful that IRQs are off during the time that the page and select
registers are being modified. This will prevent the foreground from
selecting a voice and having the background change it in the background.
2.6 Select Register - 3X3
2.6.1 Global Registers
These are the global registers. They are not voice-specific.
Address Mode Width Description
41 R/W 8 DRAM DMA Control
42 W 16 DMA Start Address
43 W 16 DRAM I/O Address (LOW)
44 W 8 DRAM I/O Address (HIGH)
45 R/W 8 Timer Control
46 W 8 Timer 1 Count
47 W 8 Timer 2 Count
48 W 8 Sampling Frequency
49 R/W 8 Sampling Control
4B W 8 Joystick trim DAC
4C R/W 8 RESET
___________________________________________________________________________
10
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.1.1 DRAM DMA Control Register - (41)
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Enable DMA (1=go)
| | | | | | +-------- DMA direction (1=read)
| | | | | +------------ DMA channel width
| | | | +---------------- \
| | | +-------------------- / DMA Rate divider
| | +------------------------ DMA IRQ Enable
| +---------------------------- (R) DMA IRQ Pending
| (W) DATA SIZE (0=8bit,1=16bit)
+-------------------------------- Invert MSB (write only)
Bit 0 - Enable the DMA channel. The GF1 will begin sending DMA ACK
protocol. If PC DMA controller is programmed, data will begin
being transferred. If not, data will move as soon as it is
programmed.
Bit 1 - DMA transfer direction. Read is taking data OUT of the
UltraSound, Write sends data to it.
Bit 2 - 0 = if DMA channel is an 8 bit channel (0-3).
1 = If it is a 16 bit channel (4-7)
Note: This is INDEPENDENT of the data size.
Bit 3,4 -DMA Rate divisor. The Maximum rate is approx 650 khz.
00 = divide by 1
01 = divide by 2
10 = divide by 3
11 = divide by 4
Bit 5 - DMA terminal count interrupt enable
Bit 6 - Read - DMA terminal count IRQ pending
Write - Data size 0 = 8 Bit data
1 = 16 bit data
Note: Data size is independent of channel size
Bit 7 - 1 = Invert High bit to flip data to twos complement form.
Note: This flips bit 7 for 8 bit data and bit 15 for
16 bit data.
2.6.1.2 DMA Start Address - (42)
Bits 15-0 are Address lines 19-4.
This register defines where the DMA will transfer data to or from. Since
only the upper 16 address bits are used and the lower 4 bits are set to 0,
a DMA transfer MUST begin on an 16 byte boundary for an 8 bit DMA channel
(0-3). If a 16 bit DMA channel is being used, the transfer MUST being on a
32 byte boundary. An additional address translation is necessary if a 16
bit DMA channel is used. For simple example code on how to do this
translation, see the C function convert_to_16().
___________________________________________________________________________
11
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.1.3 DRAM I/O Address (43,44)
These 2 registers allow you to specify an address to peek and poke directly
into UltraSound DRAM. Register 43 is the lower 16 address lines. Register
44 is the upper 4 address lines. (bits 0-3). Read or write to register 3X7
to get at the address location.
2.6.1.4 Timer Control - (45)
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Reserved (Set to 0)
| | | | | | +-------- Reserved (Set to 0)
| | | | | +------------ Enable Timer 1 IRQ
| | | | +---------------- Enable Timer 2 IRQ
| | | +-------------------- Reserved (Set to 0)
| | +------------------------ Reserved (Set to 0)
| +---------------------------- Reserved (Set to 0)
+-------------------------------- Reserved (Set to 0)
2.6.1.5 Timer 1 and Timer 2 Count - (46,47)
These counts are loaded by the application and then they will count up to
$FF and generate and IRQ. Timer 1 has a granularity of 80 microseconds
(0.00008 sec) and Timer 2 has a granularity of 320 microseconds (0.00032
sec).
2.6.1.6 Sampling Frequency - (48)
The formula for calculating this value is:
rate = 9878400/(16*(FREQ+2))
___________________________________________________________________________
12
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.1.7 Sampling Control Register - (49)
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Start sampling
| | | | | | +-------- Mode (0=mono, 1=stereo)
| | | | | +------------ DMA width (0=8bit,1=16bit)
| | | | +---------------- Reserved (Set to 0)
| | | +-------------------- Reserved (Set to 0)
| | +------------------------ DMA IRQ enable
| +---------------------------- (Read) DMA IRQ pending
+-------------------------------- Invert MSB
Bit 0 -If PC DMA controller is programmed, it will begin sampling as soon
as this is enabled.
Bit 1 -0 = mono
1 = stereo
In stereo mode, the order of the data bytes is left is first, and
right is second. If a 16 bit data channel is used, the left is in
the lower byte.
Bit 2 -DMA Channel width (0 = 8 bit, 1 = 16 bit)
Bit 5 -Enable DMA terminal count IRQ
Bit 6 -DMA terminal count IRQ pending
Bit 7 -Flip bit 7 to get non-twos compliment data
2.6.1.8 Joystick Trim DAC - (4B)
This register is initialized to 4.3 volts (value = 29). It only needs to be
modified to account for faster/slower machines. A utility is provided
(ULTRAJOY.EXE) that sets this up. There should be no reason for your
application to modify this register.
___________________________________________________________________________
13
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.1.9 Reset Register - (4C)
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Master Reset
| | | | | | +-------- DAC Enable
| | | | | +------------ GF1 Master IRQ Enable
| | | | +---------------- Reserved (Set to 0)
| | | +-------------------- Reserved (Set to 0)
| | +------------------------ Reserved (Set to 0)
| +---------------------------- Reserved (Set to 0)
+-------------------------------- Reserved (Set to 0)
Bit 0 -GF1 Master Reset. 0 = reset, 1 = run. As long as this is a 0, it
will be held in a reset state.
Bit 1 -Enable DAC output. DAC's will not run unless this bit is set.
Bit 2 -Master IRQ enable. This bit MUST be set to get ANY of the GF1-
generated IRQs (wavetable, volume, etc).
This register will normally contain the value $07 while your application is
running.
2.6.2 Voice-specific Registers
The following are the voice-specific registers. Each voice has its own bank
of read and write registers that alter its behavior. The write registers
range from 0 to F and the corresponding read registers range from 80 to 8F.
To convert from the write to the read, just add 80 hex.
Write Read Width Description
0 80 8 Voice Control
1 81 16 Frequency Control
2 82 16 Starting Address (HIGH)
3 83 16 Starting Address (LOW)
4 84 16 End Address (HIGH)
5 85 16 End Address (LOW)
6 86 8 Volume Ramp Rate
7 87 8 Volume Ramp Start
8 88 8 Volume Ramp End
9 89 16 Current Volume
A 8A 16 Current Address (HIGH)
B 8B 16 Current Address (LOW)
C 8C 8 Pan Position
D 8D 8 Volume Control
E 8E 8 Active Voices (Voice independent)
- 8F 8 IRQ Status (Voice independent)
There are several 'self-modifying' bits defined for these registers. This
means that the GF1 may change them at anytime on its own. Due to the fact
that the software must accommodate this phenomena, it is possible that the
___________________________________________________________________________
14
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
GF1 may change something immediately after your application has set/reset
one of the bits. This is due to the GF1's pipeline processor type of
architecture: it does a read-modify-write cycle, and if your application
modifies one of these bits AFTER it has done the read portion and BEFORE it
does the write portion, it's possible for the chip to perform incorrectly.
To overcome this, you need to do a double write (with a delay in between)
when those particular bits are involved. This delay must be at least 3
times the length of time necessary to process a voice. (3*1.6 microsecs).
In the lowlevel code, this is done with a function called GF1_Delay. The
self-modifying bits are designated with an (*) after the particular bit
definition.
Changing the start and end points of a voice while its playing can have
some strange side effects. For example, if you change end poistion to a
lower location than it is currently playing, you will get and IRQ (if they
are enabled). Also, since the high and low bytes are set individually and
asynchronously to when the GF1 is working on a voice, it is possible to get
an unexpected IRQ if the current position and the new end position cross.
2.6.2.1 Voice Control Register - (0,80)
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Voice Stopped
| | | | | | +-------- Stop Voice
| | | | | +------------ 16 bit data
| | | | +---------------- Loop enable
| | | +-------------------- Bi-directional loop enable
| | +------------------------ Wave table IRQ
| +---------------------------- Direction of movement
+-------------------------------- IRQ pending
* Bit 0- 1 = Voice is stopped. This gets set by hitting the end address
(not looping) or by setting bit 1 in this reg.
Bit 1- 1 = Stop Voice. Manually force voice to stop.
Bit 2- 1 = 16 bit wave data, 0 = 8 bit data
Bit 3- 1 = Loop to begin address when it hits the end address.
Bit 4- 1 = Bi-directional looping enabled
Bit 5- 1 = Enable wavetable IRQ. Generate an IRQ when the voice hits the
end address. Will generate IRQ even if looping is enabled.
* Bit 6- 1 = Decreasing addresses, 0 = increasing addresses. It is self-
modifying because it might shift directions when it hits one of
the loop boundaries and looping is enabled.
* Bit 7- 1 = Wavetable IRQ pending. If IRQ's are enabled and looping is
NOT enabled, an IRQ will be constantly generated until the voice
is stopped. This means that you may get more than 1 IRQ if it
isn't handled properly.
___________________________________________________________________________
15
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.2.2 Frequency Control Register - (1,81)
Bits 15-10 - Integer Portion
Bits 9-1 - Fractional Portion
Bit 0 - Not used.
This register determines the amount added to (or subtracted from) the
current position of the voice to determine where the next position will be.
This is how the interpolated data points are determined. If the FC register
is less than 0, the GF1 will interpolate the data point in between the two
actual data points. Note that the FC can be greater than 1. This allows for
skipping over data bytes. The actual frequency that it will play back is
directly related to the number of active voice specified (register 8E).
2.6.2.3 Starting location HIGH - (2,82)
Bits 12-0 are the HIGH 13 bits of the address of the starting location of
the waveform (Addr lines 19-7).
Bits 15-13 are not used.
2.6.2.4 Starting location LOW - (3,83)
Bits 15-9 are the low 7 bits of the address of the starting location of
the waveform. (Addr lines 6-0).
Bits 8-5 are the fractional part of the starting address.
Bits 4-0 are not used.
2.6.2.5 End Address HIGH - (4,84)
Bits 12-0 are the high 13 bits of the address of the ending location of
the waveform. (Addr lines 19-7)
Bits 15-13 are not used.
2.6.2.6 End Address LOW - (5,85)
Bits 15-9 are the low 7 bits of the address of the ending location of the
waveform. (Addr lines 6-0).
Bits 8-5 are the fractional part of the ending address.
Bits 4-0 are not used.
___________________________________________________________________________
16
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.2.7 Volume Ramp Rate - (6,86)
Bits 5-0 is the amount added to (or subtracted from) the current volume
to get the next volume. The range is from 1 to 63. The larger
the number, the greater the volume step.
Bits 7-6 defines the rate at which the increment is applied.
Please see section 2.16 for more information on hardware volume ramping.
2.6.2.8 Volume Ramp Start - (7,87)
Bits 7-4 Exponent
Bits 3-0 Mantissa
This register specifies the starting position of a volume ramp. See the
special section on volume ramping for a more complete explanation of how
this register works.
Please see section 2.16 for more information on hardware volume ramping.
2.6.2.9 Volume Ramp End - (8,88)
Bits 7-4 Exponent
Bits 3-0 Mantissa
This register specifies the ending position of a volume ramp. See the
special section on volume ramping for a more complete explanation of how
this register works.
Note: The starting volume must always be less than the ending volume. If
you want the volume to ramp down, turn on the decreasing volume
bit in the Volume Control Register.
Please see section 2.16 for more information on hardware volume ramping.
___________________________________________________________________________
17
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.2.10 Current Volume - (9,89)
* Bits 15-12 Exponent
* Bits 11-4 Mantissa
Bits 3-0 Reserved (Set to 0)
Note: This register has 4 extra bits of precision that is necessary for
finer granularity of volume placement. The extra bits are used
during a volume ramp.
Note: This is a self-modifying value. The GF1 will update this register
as it ramps.
Note: You should always set this register equal to the value of the
beginning of the volume ramp (start OR end).
Please see section 2.16 for more information on hardware volume ramping.
2.6.2.11 Current Location HIGH - (A,8A)
Bits 15-13 Reserved (Set to 0)
Bits 12-0 High 13 bits of address (address lines 19-7)
2.6.2.12 Current Location LOW - (B,8B)
Bits 15-9 Low 7 bits of address. (address lines 6-0)
Bits 8-0 9 bit fractional position.
2.6.2.13 Pan Position - (C,8C)
Bits 8-4 Reserved (Set to 0)
Bits 3-0 Pan position. (0=full left, 15=full right)
___________________________________________________________________________
18
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.2.14 Volume Ramp Control Register - (D,8D)
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Ramp Stopped
| | | | | | +-------- Stop Ramp
| | | | | +------------ Rollover condition
| | | | +---------------- Loop Enable
| | | +-------------------- Bi-directional loop enable
| | +------------------------ Volume ramp IRQ enable
| +---------------------------- Direction
+-------------------------------- IRQ pending
* Bit 0- Show the ramp has stopped
Bit 1- Manually stop the ramp.
Bit 2- Roll over condition. This bit pertains more towards the location
of the voice rather than its volume. Its purpose is to generate
an IRQ and NOT stop (or loop). It will generate an IRQ and the
voice's address will continue to move thru DRAM in the same
direction. This can be a very powerful feature. It allows the
application to get an interrupt without having the sound stop.
This can be easily used to implement a ping-pong buffer algorithm
so an application can keep feeding it data and there will be no
pops. Even if looping is enabled, it will not loop.
Bit 3- Enable looping. Loop from end to start (or start to end).
Bit 4- Enable bi-directional looping. When it hits end (or start) it
will change directions and proceed toward the other limit.
Bit 5- Enable getting an IRQ when ramp hits end.
* Bit 6- Ramp direction. 0=increasing, 1=decreasing.
* Bit 7- (READ) Volume ramp IRQ pending.
Please see section 2.16 for more information on hardware volume ramping.
2.6.2.15 Active Voices - (E,8E)
Bits 7-6 Must be set to a 1
Bits 5-0 # of voices to enable - 1.
The range is from 14 - 32. Any value less than 14 will be forced to 14.
___________________________________________________________________________
19
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.6.2.16 IRQ Source Register - (F,8F)
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +----\
| | | | | | +-------- \
| | | | | +------------ - Interrupting voice #
| | | | +---------------- /
| | | +--------------------/
| | +------------------------ 1
| +---------------------------- Volume Ramp IRQ pending
+-------------------------------- WaveTable IRQ pending
Bit 4-1-Voice # (0-31) of interrupting voice
Bit 5- ALWAYS a 1
Bit 6- 0 = Volume Ramp IRQ occurred
Bit 7- 0 = Wavetable IRQ occurred
Note: This is a global read only register. There is only 1 for ALL
voices. You MUST service any indicated IRQ's since a read of this
port will clear the associated IRQ bits in the particular voice's
control and/or volume control registers.
Note: It is possible that multiple voices could interrupt at virtually
the same time. In this case, this register will behave like a
fifo. When in your IRQ handler, keep reading (and servicing) this
register until you do a read with both IRQ bits set to a 1. This
means there are no voice IRQs left to deal with.
Note: Since it is possible to get ANOTHER IRQ from the same voice for
the SAME reason, you must ignore any subsequent IRQ from that
voice while in the IRQ handler. For example, when a voice hits its
end position and generates an IRQ back to your application, it
will continue to generate IRQ's until either the voice is stopped,
the IRQ enable is turned off, or the end location is moved.
2.7 Global Data Low - 3X4
This register can be used to do either a 16 bit transfer for one of the 16
bit wide GF1 registers (Start addr high etc) when using a 16 bit I/O
instruction or the low part of a 16 bit wide register when using an 8 bit
I/O instruction.
2.8 Global Data High - 3X5
This register is used to do either an 8 bit transfer for one of the GF1 8
bit registers or to do the high part of a 16 bit wide register.
___________________________________________________________________________
20
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.9 IRQ Status - 2X6
CAUTION: Note that this is at 2X6 *** NOT 3X6 ***.
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- MIDI Transmit IRQ
| | | | | | +-------- MIDI Receive IRQ
| | | | | +------------ Timer 1 IRQ
| | | | +---------------- Timer 2 IRQ
| | | +-------------------- Reserved (Set to 0)
| | +------------------------ WaveTable IRQ (any voice)
| +---------------------------- Volume Ramp IRQ (any voice)
+-------------------------------- DMA TC IRQ (DRAM or Sample)
2.10 Timer Control Register - 2X8
This register maps to the same location as the ADLIB board's control
register. Writing a 4 here selects the timer stuff. Bit 6 will be set if
timer #1 has expired. Bit 5 will be set it timer #2 has expired.
2.11 Timer Data Register - 2X9
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Timer 1 Start
| | | | | | +-------- Timer 2 Start
| | | | | +------------ Reserved (Set to 0)
| | | | +---------------- Reserved (Set to 0)
| | | +-------------------- Reserved (Set to 0)
| | +------------------------ Mask Timer 2
| +---------------------------- Mask Timer 1
+-------------------------------- Reset Timer IRQ
Bit 0 - Start up timer #1
Bit 1 - Start up timer #2
Bit 5 - Mask off timer 2
Bit 6 - Mask off timer 1
Bit 7 - Clear Timer IRQ
2.12 DRAM I/O - 3X7
This register is used to read or write data at the location pointed at by
registers 43 and 44. This is used to peek and poke directly to DRAM.
___________________________________________________________________________
21
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.13 Mix Control Register - 2X0
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- 0=Enable Line IN
| | | | | | +-------- 0=Enable Line OUT
| | | | | +------------ 1=Enable MIC IN
| | | | +---------------- Enable latches
| | | +-------------------- Combine chan1 IRQ with Chan2
| | +------------------------ Enable MIDI loopback TxD to RxD
| +---------------------------- Control Reg Select
+-------------------------------- Reserved (Set to 0)
Bit 0 -Enable UltraSound line Input
Bit 1 -Enable UltraSound Line output
Bit 2 -Enable Stereo Mic Input
Bit 3 -Enable latches.This provides power to the DMA/IRQ latches. Once
these are enabled, NEVER disable them. Disabling them will cause
random IRQ's in the PC since the DMA and IRQ lines are not being
driven any more.
Bit 4 -Combine Channel 1 (GF1) IRQ's with Channel 2 (MIDI)
Bit 5 -Enable MIDI loopback. Any data sent out Transmit port will be
looped back into the input port.
Bit 6 -Control Register Select. When this is set to a 1, the next IO write
to 2XB will be to the IRQ control latches. When this is set to a 0,
the next IO write to 2XB will be to the DMA channel latches. The
write to 2XB for either of these MUST occur as the NEXT IOW or else
the write to 2XB will be locked out and not occur. This is to
prevent an application that is probing for cards to accidentaly
corrupt the latches.
2.14 IRQ Control Register - 2XB
IRQ control register I/O W 2XB
(2X0- bit 6 = 1)
Bits 2-0 Channel 1 (GF1) IRQ Selector
0=No Interrupt
1=IRQ2
2=IRQ5
3=IRQ3
4=IRQ7
5=IRQ11
6=IRQ12
7=IRQ15
___________________________________________________________________________
22
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Bits 5-3 Channel 2 (MIDI) IRQ selector
0=No Interrupt
1=IRQ2
2=IRQ5
3=IRQ3
4=IRQ7
5=IRQ11
6=IRQ12
7=IRQ15
Bit 6 1 = Combine Both IRQS using Channel 1's IRQ
Bit 7 Reserved (Set to 0)
Note: If the channels are sharing an IRQ, channel 2's IRQ must be set to
0 and turn on bit 6. A bus conflict will occur if both latches are
programmed with the same IRQ #.
DMA control register I/O W 2XB
(2X0- bit 6 = 0)
Bits 2-0 DMA Select Register 1
0=NO DMA
1=DMA1
2=DMA3
3=DMA5
4=DMA6
5=DMA7
Bits 5-3 DMA Select Register 2
0=NO DMA
1=DMA1
2=DMA3
3=DMA5
4=DMA6
5=DMA7
Bit 6 - Combine Both on the same DMA channel.
Bit 7 - Reserved (Set to 0).
Note: If the channels are sharing an DMA, channel 2's DMA must be set to
0 and turn on bit 6. A bus conflict will occur if both latches are
programmed with the same DMA #.
C programmers can refer to the UltraSetInterface routine in INIT.C of the
lowlevel source code for the proper sequence for programming these latches.
If the order is not right, unpredictable things may happen.
Changing the IRQ settings will usually cause an IRQ on the OLD IRQ because
it is no longer being driven low by the latches and it will tend to float
up. That low to high transition causes an IRQ on the PC. Normally, this is
not a problem, but it is something to be aware of.
___________________________________________________________________________
23
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2.15 Register Control - 2XF
This register is only valid for UltraSound boards that are at or above
revision 3.4. It is not valid for boards which have a prior revision
number.
On 3.4 and above boards, there is a bank of 6 registers that exist at
location 2XB. Register 2XF is used to select which one is being talked to.
Register # Use
0 Same as pre-3.4 boards
1-4 Unused - Reserved
5 Write a 0 to clear IRQs on power-up
6 'Jumper register'
Jumper register definition:
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Reserved (Set to 0)
| | | | | | +-------- 1=Enable MIDI port addr decode
| | | | | +------------ 1=Enable joystick port decode
| | | | +---------------- Reserved (Set to 0)
| | | +-------------------- Reserved (Set to 0)
| | +------------------------ Reserved (Set to 0)
| +---------------------------- Reserved (Set to 0)
+-------------------------------- Reserved (Set to 0)
2.16 Volume ramping description
The UltraSound has built-in volume ramping to facilitate the implementation
of the attack decay sustain release envelopes. This ramping uses the same
principle as the voices for updating the volume values. A section of the
envelope can be programmed such that the PC does not need to be burdened
with the task of changing each volume at specified intervals. At the end
of that particular section, an IRQ can be generated so that the next
section can be programmed in.
This continues until the entire envelope has been completed. The start and
end points as well as the increment rate are fully programmable.
The hardware volume registers and bit definitions are:
Current Volume (9,89) EEEEMMMMMMMM (Bits 15-4)
Volume Start (7,87) EEEEMMMM (Bits 7-0)
Volume End (8,88) EEEEMMMM (Bits 7-0)
___________________________________________________________________________
24
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Volume Incr (6,86) RRMMMMMM (Bits 7-0)
Once the current volume, start and end volumes are programmed, the only
thing left is to set up the volume increment register. This register
determines how fast the ramp takes place and with what granularity. The
finer the granularity, the smoother (but slower) the ramp. The increment
register has 2 fields. The first is the amount added to (or subtracted
from) the current volume to get to the next one. These are the low 6 bits
and can range from 1 to 63. A 1 is a long, slow ramp compared to a 63.
The upper 2 bits determine how often the increment is applied to the
current volume. The rate bits are defined as:
Rate Bits Volume Update Rate
00 FUR (FUR = 1/(1.6*#active voices))
01 FUR/8
10 FUR/64
11 FUR/512
Each rate increment is 8 times longer than the preceding one. This means
that the value to store for the fastest possible ramp is 1Fh (63), and the
value for the slowest possible ramp is 1Ch (193). The approximate times
for a full scale volume ramp (0-4095) are:
Rate Vol Inc 14 Voices 32 Voices
---- ------- --------- ---------
0 63 1.4 ms 3.3 ms
0 1 91.7 ms 209.7 ms
1 63 11.5 ms 26.2 ms
1 1 733.8 ms 1.7 sec
2 63 91.8 ms 209.7 ms
3 1 5.9 sec 13.4 sec
3 63 734.0 ms 1.7 sec
3 1 47.0 sec 107.3 sec
Note that these times are for full sweep ramping. Since a volume ramp
usually goes between points in between the limits, the actual ramp times
will be much smaller.
Allowing to let the volume ramps to go to the extremes can cause a random
oscillation of the volume when it reaches the limits. This is caused by an
overshoot past the limit due to a large step size. The SDK routines
protect against this by limiting how close to the rails you can get.
___________________________________________________________________________
25
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Chapter 3 - Programming the UltraSound
3.0 Introduction
The UltraSound is frequently referred to as 'GUS', for Gravis' UltraSound.
The card has a very good reputation among programmers, since it is very
easy to program using a high level language, and provides incredible sound.
However, there are some things that you need to be aware of to successfully
program the board. Users of either language should consult their
respective example programs before attempting to use the card. Also, C
users should consult section 3.12, while Pascal users should consult
section 3.13.
3.1 Sound
A sound is something that you hear. It is produced by a source and received
by the ears of the listener. There are several mediums for the storage of
sound, including vinyl, magnetic surfaces, and more recently optical disks.
When something makes a sound, it creates waves of different air intensity.
These waves are registered as 'sound', and the amplitude and frequency of
these waves determine the 'type' of sound.
Amplitude is determined by the highest and lowest points of the wave, and
is registered by your ear as the volume of the sound. Therefore, the
loudness of a sound is changed by varying the amplitude of the sound's
wave. Frequency is determined by the number of pulses (passes of a single
wave peak and trough) which pass a certain point in a certain amount of
time. The measure of sound frequency is done using the standard measure
for frequency - Hertz (Hz). The higher the frequency, the higher the pitch
of the sound that is heard.
Normal sound like speech and sound that comes from mixes of different
instruments is a very complex pattern of changes in amplitude and
frequency. To record the wave's pattern, a computer takes a large number
of 'samples' of the wave produced by the sound. Then when it goes through
the individual 'samples' at the same rate they were recorded, it can
reconstruct the original wave and produce a sound which is close to the
original sound. If the sample rate is not high enough, the computer can
miss changes in the amplitude and frequency, and the sound reproduced will
not sound exactly like the original sound.
The number of samples taken each second is referred to as the 'sampling
rate', and the number of samples played back each second is referred to as
the 'playback rate'. When a rock band plays a song, the combined sound
wave produced by the singers and instruments is produced. To record this
wave at CD-quality on a computer medium (like memory or a hard disk), the
wave is 'sampled' 44100 times each second. Since the number of samples per
second is a frequency, this rate is measured again in Hertz. Therefore, we
say that the recording frequency is 44.1 kHz.
___________________________________________________________________________
26
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
If I record a sound at 44.1 kHz for two seconds, I will have 88200
individual 'samples'. The data that comprises these 'samples' is typically
referred to as a 'sample' itself.
When a recording made at 44.1 kHz is played back at 44.1 kHz, the original
sound is reproduced almost exactly. Note that the recording and playback
frequency are different from the frequency of the sound itself.
Most other sound cards do not have any RAM on them, and therefore have to
use the PC's RAM to store the sounds they produce. This leaves less room
for application programs, and is just another thing that the CPU has to
track and process - slowing down the machine.
On the UltraSound, samples are stored on the card in it's DRAM. This
leaves more space in PC RAM for programs. Also, the GF1 chip in the
UltraSound can play 32 independent sounds at once without using any CPU
time - so the machine doesn't slow down at all!
3.2 The Basics of the UltraSound
The only things you need to know to set up the card when your program
starts is the maximum # of voices you are going to need and the maximum
playback frequency you're going to need for any sample.
Consult the frequency table in section 1.3 to see how many voices you
should initialize the card with. If you don't need a large number of
voices, initializing the card to use fewer voices means that some
'oversampling' will occur, making the sound better in quality. You cannot
initialize for fewer than 14 voices or larger than 32.
To open the card, you call the UltraOpen function. This will set up the
interrupt vectors and control procedures for the card, and then reset the
card to use the number of voices you specify. When you are finished with
the card, you need to close it so that the interrupt procedures, voices,
and volumes get stopped and reset to 'normal'. To do this, call the
UltraClose function. Please see chapter 4, the reference guide, for more
information on the syntax and usage of these routines.
3.3 Using GUS Memory
The UltraSound has a default amount of 256K of memory on the card that can
be upgraded in 256K increments up to 1 MB. If you are developing for the
card, you may want to upgrade to a full megabyte. Also, you should be
aware that many users of the card do NOT have 1 MB of RAM installed, and
that if you are going to load samples into the card's memory, you need to
check to make sure you have enough room. The function UltraMaxAlloc
(additionally for Pascal users the functions UltraMemAvail and
UltraMaxAvail) will tell you how much RAM you still have available.
Because of the way the GUS memory is structured physically, you cannot
allocate chunks larger than 256k at one time.
___________________________________________________________________________
27
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
The C and Pascal versions of the SDK use different methods for keeping
track of blocks of memory that have been allocated and blocks that remain
free. The C version uses a small portion of GUS RAM to keep track of the
blocks, whereas the Pascal version uses a small amount of normal heap
space. In any event, you do not have to worry about the internal operation
of these routines. To see how the Pascal version uses a small amount of
heap space to manage GUS memory, see section 3.13.3.
The memory allocation routines will ONLY return 32 byte aligned addresses,
so if your application uses them, this will not be a problem. If you chose
not to use the allocation routines provided, be sure and follow these
rules. To obtain a legal block of UltraSound RAM that is guaranteed to be
aligned on a 32-byte boundary, use the UltraMemAlloc function. To free up
the memory after you have used it, use the UltraMemFree function. Once
again, see chapter 4, the reference guide, for more information on the
syntax and usage of these routines.
You DO NOT necessarily need to use the memory allocation and deallocation
routines to program the card. You DO have to be careful if you choose to
do without them. The DMA can only begin on a 16 or 32 byte boundary. An 8
bit DMA channel (0-3) must start on a 16 byte boundary while a 16 bit DMA
channel (4-7) must start on a 32 byte boundary. If an improper address is
supplied, the address will be truncated down when the DMA occurs. A DMA to
or from the card cannot cross a 256K boundary.
To send data from PC memory to the card, use the UltraDownload function.
To read data from the card into PC memory, use the UltraUpload function.
If you download data to the card, ensure that if the data is not in two's
compliment form you convert it to two's compliment on the download. To do
this, use the DMA control bits (see Appendix D). Any data you Upload from
the card that is playable will be in two's compliment format.
3.4 What are Samples?
As mentioned above, a 'sample' is raw data that has been recorded using the
GUS or another digital sound recording device. Most of these files will
have extensions of .SND or .WAV. There are other extensions available, but
these are the most common.
A technique known as 'frequency shifting' is sometimes used to produce
alternate 'notes' of a specified instrument. Amiga '.MOD' file players use
this technique to make a single instrument sample sound differently for
each note played over 3 octaves. Essentially, the technique utilizes the
12-note scale with the principle that each half-step is 1/12 root of 2
times the value of its predecessor in frequency (working from left to
right). For instance, if we take C as (1*frequency), C# would be
(1.05946*frequency). Since there are 12 notes in an octave, when you reach
B (the end of the octave), the next note is (2*frequency) - so doubling the
original frequency means you raise the note one octave.
___________________________________________________________________________
28
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
There is a drawback to the technique mentioned above. If a sample was
recorded at 11kHz for two seconds, and then played back at 22kHz to raise
the note one octave, it would only play for one second instead of two.
This is because you have (11025 * 2 seconds) = 22050 bytes of data. If you
play this at 22050 Hz, or 22050 bytes per second, you will have one 1
second of sound. Thus, if you raise or lower the frequency in this manner,
the sound will respectively take a shorter or longer amount of time to
play.
A common problem with samples is that the start and/or end of them is at a
reasonably high amplitude. When the sample starts and/or stops, the values
flowing through the DACs on the card change suddenly. This usually results
in an audible 'click' or 'pop' through the speakers. Section 3.8 looks at
the removal of this and other types of clicks and pops than can occur.
3.5 Using Voices
Depending on the number you choose when opening (or initializing) the card,
you can use anywhere from 14 to 32 voices at once. You can look at the
voices as those of the people in a choir. You can tell the voices to start
or stop singing (UltraStartVoice, UltraStopVoice), sing at a specified
pitch or frequency (UltraSetFrequency), loudly or softly (UltraSetVolume,
UltraSetLinearVolume), and at a specified balance (UltraSetBalance).
The exciting thing about the voices is that any number of them can be
played at once, and there is no extra drain on the CPU if you are playing a
larger number of voices as opposed to a smaller one. Also, these voices
can play any type of sampled sound, 8- or 16-bit, at frequencies up to 44.1
kHz. Any number of voices can even play the same sample at the same time.
To start up a voice, you use the UltraStartVoice or UltraPrimeVoice/
UltraGoVoice combination. Either one of these two routines will ask for a
voice number, as well as a begin, start, and end location. The reason
begin and start locations are both asked for is in case you wish to play a
sample backwards or loop at a specific position which is not the start.
The following diagram may make this clearer:
Forward playing:
================
-------->------->-------->------|
^---------<------<-|
Begin ...... Start Loop......... End Loop
location ... location ......... location
Backward playing:
=================
|------<-----<------<------<----------
|--------->----->---->---^
End Loop.... Start Loop............... Begin
location .... location ................location
___________________________________________________________________________
29
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
A voice starts at the 'begin' location, and continues playing until it hits
the 'end' location. If the 'begin' is a greater location than the 'end',
the sample will be played backwards. The 'start' location is the start of
the loop if looping is enabled for the voice begin played. Depending on
whether and how you wish to loop the voice, you can make various effects
occur. Looping of the voices is discussed in the next section.
When you have finished with a voice, You should stop it (UltraStopVoice),
and deallocate it (UltraFreeVoice). Please see section 3.8 on click
removal for information on problems with stopping a voice abruptly.
3.6 Volumes
A volume is available for each voice. If the volume for a voice is not set
to zero, the data at the position of the voice's accumulator will be summed
into the final output. Therefore, it is important that if you are not
using a voice you should set it's volume to zero.
The UltraSound uses logarithmic volumes using an exponent and a mantissa.
For detailed information about how the volumes work, please see section
2.16. As an alternative to using the logarithmic units, a table has been
provided in the lowlevel code which gives linear equivalents of the full
volume range. You can therefore use the logarithmic volume routines or the
linear volume routines - whichever your application requires.
Volumes for each voice may be 'ramped'. This means that you can specify a
start and end volume, and the card will smoothly change the volume from the
beginning level to the end level. In ramping the volumes, a 'rate' must be
specified which assigns how fast the volume is changed. Please see section
2.16 for detailed information on how to set up a volume ramp rate.
3.7 Using Looping
You can loop both voices and volumes on the UltraSound. Looping a voice
can result in sustaining a particular note, the generation of a unique
sound, or any number of other 'special effects'. Looping the volume can
result in a tremelo effect at various intervals.
Looping a sample is a simple task of setting the mode bits when specifying
the start of a voice (through UltraPrimeVoice, UltraStartVoice), or when
using UltraSetLoopMode. See appendix C for a definition of which bits in
the mode byte control looping. Also, Pascal users should be aware of the
constants that are available for use instead (see section 3.13).
Looping the volume is essentially as simple as looping a voice. When
specifying the volume for a particular voice (using UltraSetVolume or
UltraSetLinearVolume), you set the volume mode byte depending on how you
wish to loop the volume. See appendix B for a definition of which bits in
the mode byte control looping.
___________________________________________________________________________
30
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
3.8 Clicks and click removal
As was mentioned in a few of the preceding sections, 'clicks' and 'pops'
can occur when the output of the DAC changes suddenly. This is the most
frequent type of click, since there may not be a way to control the data
values the voices are trying to play.
In general, it is necessary to remember that all voices are being summed in
to the final output, even if they are not running. This means that
whatever data value that the voice is pointing at is contributing to the
summation. It is important that a voice be pointed to a known value at a
known location after it is stopped so that some control is kept over it.
For instance, if a voice were left at whereever the end position was for
the last time it played, a pop could occur if new data were either DMA'ed
or poked over the top of it. For this reason, it is recommended that a
voice be pointed to a location containing a 0 and that its volume be set to
0. At that point, the voice will have no contribution to the output.
There are some particular cases where clicks most frequently occur:
During Reset
- Because of the way the card is reset, a pop can occur through the
speakers when a reset occurs. The way to remove this pop is to disable
the output, reset the card, and then enable the output again.
During a balance sweep
- Since there are only 16 pan positions and there is such a large jump
between individual positions, a relatively fast balance sweep from one
side to another may produce clicks. You can get a very smooth balance
sweep using 2 voices and volume ramping. Set one voice up to one side
and one to the other, and ramp one down from volume X to zero at the same
rate as you ramp the other from 0 up to volume X. The result is a very
smooth balance sweep.
When starting and stopping a voice
- By setting up fairly fast rates when a sample start or ends and ramping
up or down appropriately, any pop created by a sudden change in the DAC
value will be summed in at such a low volume, it will never be heard.
End points not set properly
- Make sure your end points are at the ends of your samples. It is a very
common mistake to set an end point to 1 sample beyond the end. For
example, if a sample is 100 bytes long an starts at location 100, the end
point is at position 199, NOT position 200. Also, it is possible that
the GF1 will interpolate data at points beyond the end point. To ensure
that this does not cause 'clicks', use a few extra bytes after the end
point of the sample to maintain it.
Loop points not set properly
- The same problem as stated above (end points) is common for loop start
and end points. Be sure that the data at the end of the loop and the
beginning of the loop are practically identical, since if there is a
large step between them a click will result because the DAC value will
change suddenly.
___________________________________________________________________________
31
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
3.9 Interrupt Handling Functions
There are 9 functions (procedures for Pascal users) which can be used to
define a handler for events that happen under interrupt on the UltraSound.
These are NOT interrupt handlers but are callbacks from the interrupt
handler. This means that they should not be defined as interrupt type
functions but must adhere to the general rules of interrupt code. No DOS
calls should be made and care must be taken not to cause problems with code
running in the foreground.
UltraDramTcHandler UltraRecordHandler
UltraMIDIXmitHandler UltraMIDIRecvHandler
UltraTimer1Handler UltraTimer2Handler
UltraWaveHandler UltraVolumeHandler
UltraAuxHandler
All these routines return the old callback address so chaining could be
done if desired. This not usually necessary. It is also not necessary to
restore the handler back to the old one when exiting your application.
However, the UltraClose function MUST be called to restore the actual
interrupt handler.
These will only be CALLED if the interrupt for the particular function is
enabled in the mode parameter (see the Appendices for the bit definitions.)
It is also not necessary to set up a callback since it has a default
associated with it.
You should be able to make any SDK library calls from within the interrupt
handlers. All the library functions protect themselves from being
interrupted while doing critical operations.
3.10 Rollover feature
Each voice has a 'rollover' feature that allows an application to be
notified when a voice's playback position passes over a particular place in
DRAM. This is very useful for getting seamless digital audio playback.
Basically, the GF1 will generate an IRQ when a voice's current position is
equal to the end position. However, instead of stopping or looping back to
the start position, the voice will continue playing in the same direction.
This means that there will be no pause (or gap) in the playback. Note that
this feature is enabled/disabled thru the voice's VOLUME control register
(since there are no more bits available in the voice control registers). A
voice's loop enable bit takes precedence over the rollover. This means
that if a voice's loop enable is on, it will loop when it hits the end
position, regardless of the state of the rollover enable.
A simple example of this technique is:
1) Allocate a chunk of DRAM: 20K, for example.
2) Load the entire 20K with wave data.
3) Start up a voice with looping disabled and rollover enabled. Set its
end position to the MIDDLE of the buffer.
___________________________________________________________________________
32
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
4) When the voice hits the middle, you will get an IRQ, but the voice
will continue to play.
5) At this point, enable looping and disable the rollover. Also, set the
end position to the end of the buffer. This will make the voice loop
back to the beginning without stopping.
6) Now load the FIRST 10K with more wave data. This will make sure that
there is correct data to play when the voice loops.
7) When the voice loops, you will get and IRQ.
8) At this point, disable looping, enable rollover and set the end
position back to the middle of the buffer.
9) Now load the SECOND 10K with more wave data. This will make sure that
there is corect data to play when the rollover occurs.
10) Continue in a loop, starting at step #4.
Note:This algorithm does not take care of an initial condition where not
enough data exists to fill one complete buffer. It also doesn't
address how to finish playing the last incomplete buffer. These
points are left up to your implementation to resolve.
3.11 Stereo playback
Stereo data is represented in an interleaved format, meaning that the data
alternates between a sample for the left channel and a sample for the right
channel. It is either the responsibility of the hardware or the software
to ensure that the data gets used properly. Stereo data can be played back
two completely different ways, either under software control or hardware
control:
Software Control
================
This is the most flexible method, since it allows for playback at any
frequency. The basic algorithm is to de-interleave the data into a left
channel buffer and a right channel buffer, then send the data to two
independent voices on the card. Here is a brief description of the
algorithm that would be used:
1) Allocate 2 voices. One for left and one for right.
2) Set the left voice pan position all the way left.
3) Set the right voice pan position all the way right.
4) Set both voice volumes to the same value.
5) Allocate 2 chunks of UltraSound DRAM of the same size, say 20K apiece.
6) Read in 40K of stereo data.
7) De-interleave data into 20K of left data and 20K of right data.
8) DMA left buffer into DRAM buffer #1.
9) DMA right buffer into DRAM buffer #2.
10) Prime right voice to loop on all 20K of data forever. No IRQ.
11) Prime left voice to play 10K of its data with the rollover feature
enabled (See discussion on seamless digital playback above).
12) Start both channels up as close together as possible so they track
together. The right channel will not be touched, except to DMA new
data into its buffer.
___________________________________________________________________________
33
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
13) At this point the software will loop on the following steps until the
data is exhausted. The rollover will allow the software to play half
the buffer and get notified when it has finished, but the playback
will continue uninterrupted. When the rollover IRQ happens, the left
voice will be changed to loop at the 20K position. At this point the
software will be able to load the next 10K of left channel data into
the FIRST 10K of the left channel DRAM. The right channel is also sent
10K of data into its FIRST 10K.
14) Now each channel has the data to play when they loop at their 20K
marks.
15) When the left channel's loop IRQ happens, both the left and right
channel can be sent more data into their SECOND 10K buffer. Also, the
left channel's looping will be turned off and it will be told to
rollover at its 10K mark again. Now both channel's are ready to play
thru their 10K marks with no interruption.
16) Go back to step 13 and loop
The above algorithm does not detail the startup conditions or the shutdown
conditions.
Things that you will need to accomodate are:
1) Less than 1 buffer full of data.
2) How to terminate when data ends in first buffer. You must allow it to
loop back from the end and then stop at the end of the data instead of
rolling over at the middle. Both right and left must be taken care of.
3) How to terminate when data ends in the second buffer. After filling in
the data in the second buffer, you can turn off the rolling over at the
middle and tell it to stop at the end of the data in the second buffer.
Be sure you understand all the starting and ending possibilties when coding
you application.
The basic idea is to let the right voice loop forever on a buffer of data
and feed it data based on IRQ generated from the left channel. The left
channel can be monitored via the rollover feature to generate and IRQ at
the halfway point and an IRQ at the loop point at the end of the buffer to
know when the second buffer finishes. Data will then be sent to BOTH voices
for the portion of data that it just finished playing.
Hardware Control
================
This method has the advantage of not needing to de-interleave the data
before DMAing it into UltraSound DRAM: the data is sent to DRAM in the
interleaved format. This means that a voice must be able to play every
other sample to correctly separate the right and left channel. It is
possible to set up the GF1 and the 2 voices to do this, however, it will
only work for 2 usable freqencies. (44100 and 22050). Any other frequencies
must be done using the software control de-interleaving method.
___________________________________________________________________________
34
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
The theory behind how to achieve this is quite complex. It involves using
the # of active voices and the voice's frequency control register to get it
to grab the correct samples at the proper frequency. Here is the setup
necessary to playback 44100 Hz stereo and 22050 Hz stereo data:
44100 Hz:Set the # of active voices to 14 and set both voices playback
rate to 88200 hz.
22050 Hz:Set the # of active voices to 28 and set both voices playback
rate to 44100 hz
These two configurations will make both voices have a frequency control
register equal to 2. The frequency control register holds the amount added
to the current voice playback location to get the next playback location.
Normally, this number is a fraction so interpolation is done to generate
intermediate points between successive locations. With interleaved data, we
don't want to interpolate since the neighboring data points belong to the
other channel. We want to completely skip over the point after the current
one, and go to our current position plus 2.
The number of active voices selected will determine the update rate. The
more voices that are active, the longer time between updates, thus slowing
down the frequency. 14 active voices will give and update rate of about
22.5 microseconds (44100 hz), whereas 28 voices will give and update rate
of about 45 microseconds (22050 hz).
The intialization of the voices in this mode will obviously be different.
Essenntially, the voices must be set up to play the same data but offset
their start and end points by one or two bytes, depending on whether it is
an 8- or 16-bit sample.
3.12 C-specific information
Currently, 10 different C memory model/compiler configurations are
supplied. Large, medium, small and tiny models for Borland and Microsoft
compilers are available, as well as flat model for WatCom and MetaWare
compilers. The level 0 library contains the lowest level function calls
that talk directly to the hardware. The level 1 library is a little higher
and contains functions that call level 0 functions. The 3D libraries
contain the functions necessary for implementing the Focal Point 3D sounds.
Borland C++ 2.0 and 3.1, Microsoft C 6.0, Watcom C9.0/386, and Metaware
High C/C++ were used to test the library routines. These are the naming
conventions for the C libraries:
ultra0lb.lib Level 0, large model, Borland C
ultra1lb.lib Level 1, large model, Borland C
ult3D_lb.lib 3D, large model, Borland C
ultra0mb.lib Level 0, medium model, Borland C
ultra1mb.lib Level 1, medium model, Borland C
ult3D_mb.lib 3D, medium model, Borland C
___________________________________________________________________________
35
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
ultra0sb.lib Level 0, small model, Borland C
ultra1sb.lib Level 1, small model, Borland C
ult3D_sb.lib 3D, small model, Borland C
ultra0tb.lib Level 0, tiny model, Borland C
ultra1tb.lib Level 1, tiny model, Borland C
ult3D_tb.lib 3D, tiny model, Borland C
ultra0lm.lib Level 0, large model, Microsoft C
ultra1lm.lib Level 1, large model, Microsoft C
ult3D_lm.lib 3D, large model, Microsoft C
ultra0mm.lib Level 0, medium model, Microsoft C
ultra1mm.lib Level 1, medium model, Microsoft C
ult3D_mm.lib 3D, medium model, Microsoft C
ultra0sm.lib Level 0, small model, Microsoft C
ultra1sm.lib Level 1, small model, Microsoft C
ult3D_sm.lib 3D, small model, Microsoft C
ultra0tm.lib Level 0, tiny model, Microsoft C
ultra1tm.lib Level 1, tiny model, Microsoft C
ult3D_tm.lib 3D, tiny model, Microsoft C
ultra0wc.lib Level 0, Flat model, Watcom C
ultra1wc.lib Level 1, Flat model, Watcom C
ult3D_wc.lib 3D, Flat model, Watcom C
ultra0mw.lib Level 0, Flat model, Metaware High C/C++
ultra1mw.lib Level 1, Flat model, Metaware High C/C++
ult3D_mw.lib 3D, Flat model, Metaware High C/C++
Several example applications are supplied on the toolkit disks to show you
how to interface to the libraries. Please look them over carefully. They
are the best way to get a handle on the way the card operates.
3.13 PASCAL-specific information
Version 2.10 of the UltraSound SDK is the first version which has full
support for Turbo Pascal 6.0 and 7.0, as well as Borland Pascal 7.0. For
those of you who are curious, Borland Pascal 7.0 is the professional
version of Turbo Pascal 7.0. It costs more, but includes a lot of bells
and whistles that are not included in the regular 'Turbo' version (for more
information, contact Borland).
The translation was done entirely by Kurt Kennett of Ingenuity Software,
and is a direct translation of the C toolkit. The code was written in
Borland Pascal 7 and then minor adjustments were made to make it compile
under Turbo 6 and 7.
___________________________________________________________________________
36
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Due to the fact that the Pascal translation was done after the C code was
finished, some of the naming conventions for some of the functions and
record types reflects a 'C-like' syntax and style. Some conversion of
function result types has been done to reflect a more Pascal-like
structure.
After installation of the SDK, there will be two units and one interface
file available in the PASCAL subdirectory:
ULTRADRV.V60 Turbo Pascal 6.0 version
ULTRADRV.V70 Turbo/Borland Pascal 7.0 version
ULTRADRV.INT This is the interface section for all units.
You should copy the unit you wish to use to one of your unit directories,
and then rename the unit to 'ULTRADRV.TPU'. You may experience compiling
problems if you do not rename the file. You may also wish to copy the
interface file to use as a quick-reference.
For users of Turbo and Borland Pascal 7.0, a help file has been provided to
allow quick context-sensitive help from inside the IDE editor. Also, a
MAKEHELP.TXT version of this help file has been provided for those users
who employ TurboPower's context-sensitive help system.
To install the IDE help file, load Turbo or Borland Pascal 7 and select the
'Help' menu from the menu bar. Choose the 'Files...' option, and select
the 'Add' button. Choose the file 'ULTRADRV.TPH' from the UltraSound
PASCAL subdirectory. After you have done this, you may use the F1 key and
it's derivatives to access reference information for any of the functions
and procedures in the SDK reference manual (chapter 3).
For example, after installing the help file, type the word
'UltraSetFrequency' into the IDE, move the cursor on top of the word, and
press CTRL-F1. You will be given an explanation of the syntax and usage of
the Procedure, as well as information on related procedures, functions,
constants, and variables.
A short section detailing specific information about types and constants
available follows. For more information, please see the interface file
ULTRADRV.INT.
3.13.1 Available constants and variables
The SDK TPU (or 'driver') has some predefined constants to assist you in
programming various aspects of the card. There are three common
frequencies that sampled sounds are played at: 11, 22, and 44 KHz:
Khz_11 = 11025;
Khz_22 = 22050;
Khz_44 = 44100;
___________________________________________________________________________
37
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Whenever volume is specified, there is a volume control byte. The bits in
this byte control several important functions. OR the following constants
together with zero if you need them. If you don't, just specify zero as
the volume control byte:
Loop_Volume = 08;
Bi_Directional_Volume = 16;
Enable_Volume_Handler = 32;
Whenever a voice is started or changed, there is a voice control byte. The
bits in this byte control several important functions for each voice. OR
the following constants together with zero if you need them. If you don't,
just specify zero as the voice control byte:
Voice_Data_16Bit = 04;
Loop_Voice = 08;
Bi_Directional_Voice = 16;
Enable_VoiceEnd_Handler = 32;
When a DMA transfer is started, you need to tell the DMA controller what
type of data you are sending to the UltraSound, as well as if the
controller should convert the data to 2's complement. If you are
downloading ram .SND files to the card, you need to OR the Convert_Data
constant to 0 as the control byte. If you are downloading 16 Bit data, you
need to OR the control byte with DMA_Data_16Bit.
DMA_Data_16Bit = 64;
Convert_Data = 128;
There are several predefined variables to help you manage the UltraSound
card as you use it. These variables determine the Configuration, error
codes, and whether or not the card is installed:
Ultra_Installed : BOOLEAN;
If the driver cannot read the environment variable 'ULTRASND' when it is
initialized (i.e. when your program starts), this BOOLEAN will remain
false. Otherwise, the variable Ultra_Config (see below) will be set up
with the values found in the environment variable.
Ultra_Config : Ultra_CFG;
If the driver was able to read a configuration from the 'ULTRASND'
environment variable, this variable record will be filled in with the
appropriate information found in the environment. If the environment
string is not found, this variable will assume a default configuration.
All of the functions and procedures in the driver use this configuration to
initialize and use the card. Be careful if you're going to go sticking
values into this record. The main use of this variable is to display the
active configuration to the user.
___________________________________________________________________________
38
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
The driver predefines three variables to help you with error control:
UltraOk : Boolean;
This boolean always maintains the status of the last UltraSound procedure
or function. If there was a problem with the routine, this variable will
be FALSE. Otherwise, it will be TRUE (indicating no error).
UltraError : Integer;
This is the "Error Code" of the Error. This variable is set to 0 if no
error has occurred, and is only set when UltraOk becomes FALSE.
UltraErrorStr : String;
This is the "description" of the error which has occurred. As an added
bonus to you, the programmer, this string is set with a (descriptive) error
message whenever a card-related error occurs.
3.13.2 Examples
There are several example programs included with the units described in the
previous section:
GUSINIT.PAS
This example file is a small unit that you may want to use to initialize
the GUS before you use it. The important thing about this unit is that it
installs an 'Exit Procedure' which is called upon program termination
(normal or crash-out). The exit procedure closes down the card before
returning to DOS (or the IDE, depending upon where you are). In TP and BP
7, you can type 'ExitProc' into the IDE, move the cursor on top of it, and
hit CTRL-F1 for a detailed explanation of what an exit procedure is. After
including this unit in your 'uses' clause, your main program can just go
ahead and start using it. You don't need to call UltraOpen, UltraReset, or
even UltraClose when you're finished.
GUS1.PAS
This is the primitive example program for the card which loads three sounds
(a laser blast, a photon torpedo, and a missile) into the card's RAM and
then allows you to press the '1'..'3' keys to play them. This example uses
the GUSINIT unit - showing you how easy it is to use.
LOADMOD.PAS
This is a unit which provides services to load Amiga '.MOD' files into GUS
RAM and main memory. After calling a single function, the file will have
been loaded and the samples contained in it set up to play. It is left up
to you to supply playback routines or trivial sample-playing routines.
___________________________________________________________________________
39
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
3.13.3 Management of GUS RAM.
The Pascal version of the SDK employs a different approach to memory
control than the C toolkit. In the C SDK, a small amount of the GUS RAM is
used to keep track of allocated blocks. In the Pascal SDK, a very small
amount of heap space is used to keep track of the blocks.
Because of the way the UltraSound RAM is structured, any particular card
has a total amount of installed RAM that is a multiple of 256k. Since
samples cannot be played across these boundaries, the driver unit divides
the total RAM by 256k into 1 to 4 'pools'.
|--------------------------------------|
| | 256k (a single 'pool')
|--------------------------------------|
Each of these pools is seen as a single unit which can be subdivided. For
the purposes of this example, we will use a GUS which has 512k installed.
If this is the case, there will be two pools of RAM available:
|--------------------------------------|
| | Pool 1
|--------------------------------------|
| | Pool 2
|--------------------------------------|
Once the card has been initialized, there will be a small amount of heap
space being used to keep track of these pools (usually less than 100
bytes). At this point, the UltraMaxFree function will return 256k, since
the size of the largest block that can be allocated is one entire pool.
The UlraMemAvail function will return 512k however, reflecting the total
amount of memory still available.
If a user were to allocate a 128k chunk of memory, the allocation routines
would look in each pool sequentially until a pool is found with enough room
for the new block. At this point in our example, it would use Pool 1.
|----------------------------------------|
|XXXXXXXXXXXXXXXXXXXX | Pool 1
|----------------------------------------|
| | Pool 2
|----------------------------------------|
The X's in the diagram above reflect used space. If the size of the block
being allocated is not divisible by 32, the actual size of the block in
memory is increased to the next multiple of 32. For example, if I were to
ask for a 50 byte chunk of RAM, the actual size of ram that I would be
using would be 64 bytes in size. This is so that all memory locations
returned will be aligned on a 32-byte boundary. At this point, the
UltraMaxFree function will return 256k, since the size of the largest block
that can be allocated is still one entire pool (Pool 2). The UltraMemAvail
function will return 384k, reflecting the total amount of memory still
available.
___________________________________________________________________________
40
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
If a user were to now allocate a 200k chunk of memory, the allocation
routines would once again look in each pool sequentially until a pool is
found with enough room for the new block. At this point in our example, it
would have to use Pool 2, since there is not enough room left in Pool 1.
|----------------------------------------|
|XXXXXXXXXXXXXXXXXXXX | Pool 1
|----------------------------------------|
|YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY | Pool 2
|----------------------------------------|
At this point, the UltraMaxFree function would return 128k, since the
largest block free is in Pool 1. UltraMemFree would now return 184k. If
we were to allocate a third block of 70k, the diagram would look like:
|----------------------------------------|
|XXXXXXXXXXXXXXXXXXXXZZZZZZZZZZ | Pool 1
|----------------------------------------|
|YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY | Pool 2
|----------------------------------------|
If we were to now DEallocate the first block (the X's in the diagram), we
would be left with a 'hole' in the ram. This is reminiscent of a hard
disk's free space fragmentation.
|----------------------------------------|
| ZZZZZZZZZZ | Pool 1
|----------------------------------------|
|YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY | Pool 2
|----------------------------------------|
Note that the SDK's memory allocation routines do NOT relocate samples to
fend off fragmentation. Note also that the memory routines are set up and
are ready to be used as soon as you call UltraOpen, and are closed down
automatically (and the heap space they use deallocated) when you call
UltraClose.
3.14 Coming Attractions
There are a couple of addendums to the SDK that will be released as they
are completed. They deal with hardware that is in the process of being
implemented. Code and documentation necessary to make them operate will be
made available as soon as possible.
1) New mixer. All UltraSounds that are made that have a board revision
number greater than 3.6 will incorporate a new mixer. Basically, this
mixer allows software control over the levels of the input and output
signals. This is a 1 chip mixer: Gravis will make specs and block diagrams
available as soon as we can.
___________________________________________________________________________
41
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
2) 16 bit recording support. This falls into 2 categories: daughter card
support and UltraMax support. Both of these use the same chip (Crystal
Semiconductors CS4231 CODEC). Contact Crystal to get a data sheet for
specs on how to program it: their telephone number is (512) 445-7222. The
only difference in the 16 bit recording capabilities of the 2 cards is in
how it interfaces to the rest of the UltraSound card. Block diagrams for
both of these boards will be made available when the toolkit for the codec
is released.
3.15 Technical Support
Questions regarding the SDK can be sent to:
SDK Technical Support
Advanced Gravis
101-3750 North Fraser Way
Burnaby, British Columbia V5J 5E9
FAX (604) 431-5155
If you have access to a modem, you can contact Gravis' BBS at:
(604) 431-5927
If you have access to internet mail services, you can send mail to
'john.smith@gravis.com' for general questions, or 'kurt.kennett@gravis.com'
for questions regarding the Pascal version of the SDK.
Please make sure you have consulted this documentation before contacting
Technical support. (RTFM!)
___________________________________________________________________________
42
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Chapter 4 - Reference Guide
This chapter is a reference guide for the routines that compromise both the
C and Pascal versions of the SDK. Please see the table of contents to look
up a particular routine quickly by name.
UltraCalcRate
_________________________________
Purpose: To calculate the rate for a volume ramp.
C: unsigned char UltraCalcRate(start,end,mil_secs);
unsigned int start;
unsigned int end;
unsigned long mil_secs;
PASCAL: FUNCTION UltraCalcRate(StartV : WORD;
EndV : WORD;
Mil_Secs : LONGINT) : BYTE;
Remarks: This routine calculates the rate necessary to ramp the volume
from StartV volume (logarithmic) to EndV volume (logarithmic)
in a desired # of milliseconds. This value should be passed to
UltraRampVolume. This is only an approximation. The longer
the time span, the less precise the result is likely to be.
Returns: A value which can be passed to UltraRampVolume or
UltraRampLinearVolume.
See also: UltraRampVolume, UltraRampLinearVolume
UltraClose
_________________________________
Purpose: To close out the UltraSound card.
C: int UltraClose(void);
PASCAL: FUNCTION UltraClose : BOOLEAN;
Remarks: This routine should be called before your application exits.
It shuts down all audio and puts the card in a stable state.
It also puts the PC back to the state prior to running your
application (resets interrupt vectors etc).
Returns: TRUE if Close was successful, FALSE otherwise.
See also: UltraOpen, UltraReset
___________________________________________________________________________
43
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraDownload
_________________________________
Purpose: Download a chunk of data into UltraSound DRAM.
C: int UltraDownload(dataptr,control,dram_loc,len,wait);
void *dataptr;
unsigned char control;
unsigned long dram_loc;
unsigned int len;
int wait;
PASCAL: FUNCTION UltraDownLoad(DataPtr : POINTER;
Control : BYTE;
DRAM_Loc : LONGINT;
Len : WORD;
Wait : BOOLEAN) : BOOLEAN;
Remarks: This routine will transfer a chunk of data from the PC's RAM to
the UltraSound's DRAM. It will transfer 'Len' # of bytes from
DataPtr (in PC) to DRAM_Loc (in UltraSound). If 'Wait' is
TRUE, then it will wait until the transfer is complete. If
'Wait' is FALSE, it will return as soon as transfer is started.
In some cases where you need to get output quickly, you can
start the download and then immediately start a voice playing
the data. The DMA transfer is MUCH faster than the voice
playback, so it will be able to download data ahead of the
playback. For obvious reasons, this will not work if you want
to play the data backwards. See Appendix D for a definition of
the control bits. They specify the type of data being
transferred.
Returns: C: ULTRA_OK if no problem.
DMA_BUSY if DMA Channel is busy.
PASCAL: TRUE if transfer was successful. FALSE otherwise.
If unsuccessful, check UltraErrorStr for the reason.
See also: UltraUpload, UltraDRAMDMABusy
___________________________________________________________________________
44
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraDRAMDMABusy
_________________________________
Purpose: Test to see if the DMA channel is busy.
C: int UltraDramDMABusy(void);
PASCAL: FUNCTION UltraDRAMDMABusy : BOOLEAN;
Remarks: This routine will check to see if the to/from DRAM DMA channel
is busy. It might be useful so your application doesn't hang
around while waiting for a DMA transfer to complete.
Returns: TRUE if the channel is still busy. FALSE if it's free.
See also: UltraWaitDRAMDMA, UltraDownload, UltraUpload
UltraGoRecord
_________________________________
Purpose: To start up a pre-set record.
C: int UltraGoRecord(control);
unsigned char control;
PASCAL: FUNCTION UltraGoRecord(Control : BYTE) : BOOLEAN;
Remarks: This routine will start up a pre-primed record (done with
UltraPrimeRecord). It can also be used to restart a indefinite
recording process from the recording handler callback.
Returns: C: ULTRA_OK if no error
DMA_BUSY if the channel is busy
PASCAL: TRUE if Record started ok. FALSE otherwise.
If FALSE check the UltraErrorStr for the reason.
See also: UltraRecordData, UltraPrimeRecord, UltraRecordHandler
___________________________________________________________________________
45
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraGoVoice
_________________________________
Purpose: To start a voice that has already been primed.
C: void UltraGoVoice(voice,mode);
int voice;
unsigned char mode;
PASCAL: PROCEDURE UltraGoVoice(Voice : INTEGER;
VMode : BYTE);
Remarks: This routine will start up a voice that has already been primed
with set-up values by UltraPrimeVoice. This can be useful if
you need to start multiple voices as close together as
possible. See Appendix C for the mode bit definitions.
See also: UltraPrimeVoice, UltraStartVoice
UltraDisableLineIn
_________________________________
Purpose: To disable line level input.
C: void UltraDisableLineIn(void);
PASCAL: PROCEDURE UltraDisableLineIn;
Remarks: If line level input is enabled and output is enabled, the input
is routed directly to the output and audio will be heard. If
this is not desired, use this to disable line in.
See also: UltraEnableLineIn, UltraGetLineIn
UltraDisableMicIn
_________________________________
Purpose: To disable microphone input.
C: void UltraDisableMicIn(void);
PASCAL: PROCEDURE UltraDisableMicIn;
Remarks: If microphone input is enabled and output is enabled, the input
is routed directly to the output and audio will be heard. If
this is not desired, use this to disable microphone in.
See also: UltraEnableMicIn, UltraGetMicIn
___________________________________________________________________________
46
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraDisableOutput
_________________________________
Purpose: To turn off all output from the UltraSound.
C: void UltraDisableOutput(void);
PASCAL: PROCEDURE UltraDisableOutput;
Remarks: This routine will disable all output from the UltraSound. This
can be used during recording so that the input will not be
looped back to the output. It is also useful to disable output
during resets since that will help eliminate 'pops' during
initialization.
See also: UltraEnableOutput, UltraGetOutput
UltraEnableLineIn
_________________________________
Purpose: To enable line level input.
C: void UltraEnableLineIn(void);
PASCAL: PROCEDURE UltraEnableLineIn;
Remarks: Turns on the line level input. If you are not recording from
the line input, it is probably not desirable to have this
enabled since it will be looped back to the output (if output
is enabled).
See also: UltraDisableLineIn, UltraGetLineIn
UltraEnableMicIn
_________________________________
Purpose: To turn on the microphone input.
C: void UltraEnableMicIn(void);
PASCAL: PROCEDURE UltraEnableMicIn;
Remarks: This routine should be called when you want to record from the
microphone. It is possible to have both the microphone input
enabled and line level input enabled. If you are not recording
from the microphone, it is recommended that it be disabled,
since it will reduce noise on the output.
See also: UltraDisableMicIn, UltraGetMicIn
___________________________________________________________________________
47
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraEnableOutput
_________________________________
Purpose: To enable output from the UltraSound.
C: void UltraEnableOutput(void);
PASCAL: PROCEDURE UltraEnableOutput;
Remarks: This routine must be called to enable any output from the
UltraSound. This can be used to turn on output after muting it
with UltraDisableOutput.
See also: UltraDisableOutput, UltraGetOutput
UltraGetLineIn
_________________________________
Purpose: To return the current state of line level input
C: int UltraGetLineIn(void);
PASCAL: FUNCTION UltraGetLineIn : BOOLEAN;
Remarks: This can be useful if you want to change the state of the line
level input and then restore it back to the original state.
Returns: TRUE if LineIn is Enabled, FALSE otherwise.
See also: UltraEnableLineIn, UltraDisableLineIn
UltraGetOutput
_________________________________
Purpose: To return the current output enabled state.
C: int UltraGetOutput(void);
PASCAL: FUNCTION UltraGetOutput;
Remarks: This can be useful if you want to change the state of the
output and then restore it back to the original state.
Returns: TRUE if Output is Enabled, FALSE otherwise.
See also: UltraEnableOutput, UltraDisableOutput
___________________________________________________________________________
48
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraGetMicIn
_________________________________
Purpose: To return the current state of the microphone input.
C: int UltraGetMicIn(void);
PASCAL: FUNCTION UltraGetMicIn;
Remarks: This can be useful if you want to change the state of the
microphone input and then restore it back to the original
state.
Returns: TRUE if Output is Enabled, FALSE otherwise.
See also: UltraEnableMicIn, UltraDisableMicIn
___________________________________________________________________________
49
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraDRAMTcHandler
_________________________________
Purpose: To define a callback for a DMA transfer completion.
C: PFV *(UltraDramTcHandler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraDRAMTcHandler(VAR Handler : PFV);
Remarks: This procedure defines a callback for whenever a DMA transfer
to the UltraSound has been completed. The routine address
passed as a parameter is set as the new handler. No parameters
are passed to your new handler.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: Since PASCAL cannot return function or procedure type values
from functions, the equivalent routine was made into a
procedure which took a single VAR parameter. Thus, when you
are going to change the address of a callback routine, you put
the new address into a variable, run it through the procedure,
and what will then be in the variable is the address of the old
handler:
VAR
OldProc : PFV;
Procedure MyNewProc;
{ The new handler - defined as a normal procedure }
begin
...
end;
...
{ Set OldProc to address of new handler }
OldProc := MyNewProc;
{ Now set the new handler and return the old one }
UltraDRAMTcHandler(OldProc);
...
At this point, OldProc holds the address of the old routine.
Therefore, to chain to the old routine, you would simply have
to call OldProc from your handler.
___________________________________________________________________________
50
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraMIDIXmitHandler
_________________________________
Purpose: To define a callback for MIDI transmit interrupt.
C: PFV *(UltraMIDIXmitHandler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraMIDIXMitHandler(VAR Handler : WORD_PROC);
Remarks: This procedure defines a callback for whenever a MIDI transmit
empty interrupt occurs. This can be used to send out MIDI data
under interrupt control. The routine address passed as a
parameter is set as the new handler. The MIDI Status Byte is
passed to the new handler defined.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: See the example for UltraDRAMTcHandler.
See also: UltraMIDIRecvHandler
UltraMIDIRecvHandler
_________________________________
Purpose: To define a callback for a MIDI receive interrupt.
C: PFV *(UltraMIDIRecvHandler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraMIDIRecvHandler(VAR Handler : TWOWORD_PROC);
Remarks: This procedure defines a callback for whenever a byte is
received in the MIDI input port. This can be used to get data
from the MIDI port under interrupt contol. The routine address
passed as a parameter is set as the new handler. The MIDI port
status and MIDI data are passed to your handler. The status
bits are defined in Appendix D.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: See the example for UltraDRAMTcHandler.
See also: UltraMIDIXmitHandler
___________________________________________________________________________
51
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraTimer1Handler
_________________________________
Purpose: To define a callback from Timer #1.
C: PFV *(UltraTimer1Handler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraTimer1Handler(VAR Handler : PFV);
Remarks: This procedure defines a callback for whenever the UltraSound's
Timer 1 'Ticks'. The routine address passed as a parameter is
set as the new handler. No parameters are passed to this
handler.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: See the example for UltraDRAMTcHandler.
See also: UltraTimer2Handler, UltraStartTimer
UltraTimer2Handler
_________________________________
Purpose: To define a callback for Timer #2.
C: PFV *(UltraTimer2Handler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraTimer2Handler(VAR Handler : PFV);
Remarks: This procedure defines a callback for whenever the UltraSound's
Timer 2 'Ticks'. The routine address passed as a parameter is
set as the new handler. No parameters are passed to this
handler.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: See the example for UltraDRAMTcHandler.
See also: UltraTimer1Handler, UltraStartTimer
___________________________________________________________________________
52
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraWaveHandler
_________________________________
Purpose: To define a callback for an end-of-wave interrupt.
C: PFV *(UltraWaveHandler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraWaveHandler(VAR Handler : INT_PROC);
Remarks: This procedure defines a callback for whenever a voice
generates a wavetable interrupt. This happens when a voice
hits it's end and interrupts are enabled. It will happen even
if looping is on (i.e. the voice keeps playing). The routine
address passed as a parameter is set as the new handler.
Normally, This procedure is used to signify that a voice is
done playing. This handler can be useful for starting another
voice or counting the # of times that a voice goes through a
loop. The voice # that generated the interrupt is passed back
to your handler.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: See the example for UltraDRAMTcHandler.
UltraVolumeHandler
_________________________________
Purpose: To define a callback for volume ramp complete interrupt.
C: PFV *(UltraVolumeHandler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraVolumeHandler(VAR Handler : INT_PROC);
Remarks: This procedure defines a callback for whenever a volume ramp
ends. The routine address passed as a parameter is set as the
new handler. This routine can be used to generate a volume
envelope (attack, decay, sustain, release). This is done by
changing to the appropriate volume ramps in the handler to
handle the next part of the envelope. The voice # causing the
interrupt will be passed back to your handler.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: See the example for UltraDRAMTcHandler.
___________________________________________________________________________
53
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraRecordHandler
_________________________________
Purpose: To define a callback for a DMA record complete interrupt.
C: PFV *(UltraUltraRecordHandler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraRecordHandler(VAR Handler : PFV);
Remarks: This routine is called when a buffer that was being recorded
into is full. The routine address passed as a parameter is set
as the new handler. Normally, this procedure would be used to
let the application start up another record. A double
buffering scheme could be used to record data continuously. No
parameters are passed to this handler.
As long as the DMA channels for recording and playback are
different, the UltraSound is capable of simultaneously
recording and playback. At high data rates your application
may have a problem with throughput.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: See the example for UltraDRAMTcHandler.
UltraAuxHandler
_________________________________
Purpose: To define a callback for an auxiliary interrupt.
C: PFV *(UltraUltraAuxHandler(handler));
PFV *handler;
PASCAL: PROCEDURE UltraAuxHandler(VAR Handler : PFV);
Remarks: This handler will be called at the end of ALL interrupts that
happen on the UltraSound. Its primary purpose is for use with
the new UltraMax card since its shares its IRQ with the GF1.
Returns: For C users, this routine returns the address of the old
handler.
PASCAL
Example: See the example for UltraDRAMTcHandler.
___________________________________________________________________________
54
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraMaxAlloc
_________________________________
Purpose: To find the size of the largest allocatable block of UltraSound
DRAM.
C: unsigned long UltraMaxAlloc(void);
PASCAL: FUNCTION UltraMaxAlloc : LONGINT;
Remarks: This routine will return the largest block of DRAM (in bytes)
that can still be allocated. This can be useful for
determining whether or not a patch or sample can be loaded.
The maximum size of a block is 256K.
Returns: # of bytes in largest available block.
See also: UltraMemAlloc, UltraMemFree,
for C users UltraMemInit
and for PASCAL users UltraMemAvail and UltraMaxAvail
UltraMaxAvail
_________________________________
Purpose: To find the size of the largest allocatable block of UltraSound
DRAM.
C: Use the UltraMaxAlloc function.
PASCAL: FUNCTION UltraMaxAvail : LONGINT;
Remarks: This routine will return the largest block of DRAM (in bytes)
that can still be allocated. This can be useful for
determining whether or not a patch or sample can be loaded.
The maximum size of a block is 256K. This routine is included
to provide consistency of naming for PASCAL Programmers.
Returns: # of bytes in largest available block.
See also: UltraMemAlloc, UltraMemFree,
for C users UltraMemInit
and for PASCAL users UltraMemAvail
___________________________________________________________________________
55
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraMemAvail
_________________________________
Purpose: To find the total amount of free UltraSound DRAM.
C: This function is not available.
PASCAL: FUNCTION UltraMemAvail : LONGINT;
Remarks: For PASCAL users, this will return the total amount of DRAM
still available for use on the UltraSound.
Returns: # of bytes in left available.
See also: UltraMemAlloc, UltraMemFree, UltraMaxAlloc
for C users UltraMemInit
and for PASCAL users UltraMaxAvail
UltraMemAlloc
_________________________________
Purpose: To safely allocate a chunk of UltraSound DRAM.
C: int UltraMemAlloc(size, location);
unsigned long size;
unsigned long *location;
PASCAL: FUNCTION UltraMemAlloc( Size : LONGINT;
VAR Location : LONGINT) : BOOLEAN;
Remarks: This routine allocates a chunk of DRAM of 'Size' bytes from the
UltraSound's DRAM. The memory allocation structures are set up
by UltraOpen. 'Location' is filled in with the DRAM location
of the start of the chunk of memory. The memory address
returned will ALWAYS be aligned on a 32 byte boundary so that
the DRAM can be DMA'ed into without error. Also, the size will
be rounded UP to the next 32 byte boundary. PASCAL users can
reference section 1.8.3 for a detailed look at how the memory
is managed.
Returns: C: ULTRA_OK if no problem.
NO_MEMORY if there is no chunk of DRAM large enough.
PASCAL: TRUE if the allocation was successful.
If FALSE, check UltraErrorStr for the reason.
See also: UltraMemFree, UltraMaxAlloc,
for C users UltraMemInit
and for PASCAL users UltraMaxAvail and UltraMemAvail
___________________________________________________________________________
56
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraMemFree
_________________________________
Purpose: To free a chunk of DRAM previously allocated with
UltraMemAlloc.
C: int UltraMemFree(size,location);
unsigned long size;
unsigned long location;
PASCAL: FUNCTION UltraMemFree(Size : LONGINT;
Location : LONGINT) : BOOLEAN;
Remarks: Frees a previously allocated chunk of UltraSound memory. The
size will automatically be rounded UP to the next 32 byte
boundary.
Returns: C: ULTRA_OK if no problem.
CORRUPT_MEM if the memory structures are corrupted.
PASCAL: TRUE if deallocation was successful.
If FALSE, check UltraErrorStr for the reason.
See also: UltraMemInit, UltraMemAlloc
for C users UltraMemInit
and for PASCAL users UltraMaxAvail and UltraMemAvail
UltraMemInit
_________________________________
Purpose: To initialize or re-initialize the memory pool structures.
C: unsigned long UltraMemInit(void);
PASCAL: This routine is not used. The unit automatically calls these
routines when your program starts.
Remarks: This routine sets up the UltraSound DRAM so that UltraMemAlloc
and UltraMemFree will work. It is called in UltraOpen. It can
be called at any time if an application wants to clean up all
its allocated or corrupted memory structures.
Returns: Number of K of DRAM found on the UltraSound. If an application
wishes to reserve a chunk of DRAM outside of the memory pool, a
variable called _ultra_reserved_dram must be set up with the #
of bytes to reserve BEFORE UltraMemInit is called. This
reserved chunk will start at 0. The reserved chunk must be
greater than 32 bytes and less than 256K in size.
See also: UltraMemAlloc, UltraMemFree, and UltraMaxAlloc
___________________________________________________________________________
57
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraMIDIDisableRecv
_________________________________
Purpose: To disable the MIDI receive data interrupt.
C: void UltraMIDIDisableRecv(void);
PASCAL: PROCEDURE UltraMIDIDisableRecv;
Remarks: This routine will disable the receive data interrupts from the
MIDI. If the interrupt is enabled, it should be disabled
before leaving your application.
See also: UltraMIDIEnableRecv, UltraMIDIRecvHandler
UltraDisableMIDIXmit
_________________________________
Purpose: To disable MIDI transmit interrupts.
C: void UltraDisableMIDIXmit(void);
PASCAL: PROCEDURE UltraDisableMIDIXmit;
Remarks: This routine will turn off MIDI transmit interrupts. It MUST
be called when you are through sending data.
See also: UltraMIDIXmitHandler, UltraMIDIEnableXmit
UltraMIDIEnableRecv
_________________________________
Purpose: To enable receive data interrupts for MIDI port.
C: void UltraMIDIEnableRecv(void);
PASCAL: PROCEDURE UltraMIDIEnableRecv;
Remarks: This routine will enable receive data interrupts from the MIDI
port. It is necessary to set up a callback routine for your
application to process the data.
See also: UltraMIDIRecvhandler, UltraMIDIDisableRecv
___________________________________________________________________________
58
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraEnableMIDIXmit
_________________________________
Purpose: To enable transmit interrupts from MIDI.
C: void UltraEnableMIDIXmit(void);
PASCAL: PROCEDURE UltraEnableMIDIXmit;
Remarks: This routine will enable transmit data interrupts to be
generated as each byte is transmitted out the MIDI port. Note
that a transmit interrupt will be generated as soon as the IRQ
is enabled unless a byte is sent out immediately prior to
enabling it. This is because the xmit buffer is initially
empty (unless primed) so it will pop an interrupt. Also note
that you MUST disable this interrupt when you are not sending
any more data or else you will be hung up getting transmit
ready interrupts.
See also: UltraMIDIXmitHandler, UltraMIDIDisableXmit
UltraMIDIRecv
_________________________________
Purpose: To read a byte from the MIDI port.
C: unsigned char UltraMIDIRecv(void);
PASCAL: FUNCTION UltraMIDIRecv : BYTE;
Remarks: This routine is used to read a byte from the MIDI port. It
assumes that the byte is waiting. The Byte is there if it got
to the MIDI receive interrupt callback routine or if you have
polled the status and determined the receive buffer is full.
Returns: MIDI data byte
See also: UltraMIDIRecvHandler, UltraMIDIStatus
___________________________________________________________________________
59
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraMIDIReset
_________________________________
Purpose: To reset the MIDI port.
C: void UltraMIDIReset(void);
PASCAL: PROCEDURE UltraMIDIReset;
Remarks: This routine should be used to ensure that the MIDI port is
ready to use. All MIDI interrupts will be disabled by this
call.
See also: UltraEnableMIDIXmit, UltraEnableMIDIRecv
UltraMIDIStatus
_________________________________
Purpose: To read the MIDI status byte.
C: unsigned char UltraMIDIStatus(void);
PASCAL: FUNCTION UltraMIDIStatus : BYTE;
Remarks: This routine returns the current MIDI port status bits. This
can be used to determine if an error has occurred or if the
port is ready to be read or written.
Returns: The MIDI status byte. See chapter 2.
See also: UltraMIDIXmit, UltraMIDIRecv
UltraMIDIXmit
_________________________________
Purpose: To send a byte out the MIDI port.
C: void UltraMIDIXmit(data);
unsigned char data;
PASCAL: PROCEDURE UltraMIDIXmit(Data : BYTE);
Remarks: This routine will send the 'Data' byte out the MIDI data port.
If interrupts are enabled, an interrupt will be generated when
the Byte has been transmitted.
See also: UltraMIDIXmitHandler
___________________________________________________________________________
60
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraOpen
_________________________________
Purpose: To open and initialize the UltraSound card and the SDK code.
C: int UltraOpen(config,voices);
ULTRA_CFG *config;
int voices;
PASCAL: FUNCTION UltraOpen(VAR Config : Ultra_CFG;
Voices : INTEGER) : BOOLEAN;
Remarks: This routine should ALWAYS be called to initialize the
UltraSound. It will probe for the card and program the IRQ and
DMA latches. It will then disable line and microphone input
and enable output. It also initializes the memory structures.
The # of active voices is an important parameter to the
UltraSound: the fewer the # of voices, the more oversampling
that occurs on playback. This will make the sound much
'cleaner'. If you specify a number of voices less than 14, the
card will still be initialized to use 14 voices. Likewise, if
you select larger than 32 voices, you will still only have 32.
Returns: C: ULTRA_OK if no problem.
NO_ULTRA if no UltraSound card found.
BAD_NUM_OF_VOICES if # of active voices out of range
PASCAL: TRUE if the card was successfully opened.
If FALSE, check UltraErrorStr for the reason.
See also: UltraClose, UltraProbe
___________________________________________________________________________
61
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraPeekData
_________________________________
Purpose: To examine any DRAM location on the UltraSound.
C: unsigned char UltraPeekData(baseport,location);
unsigned int baseport;
unsigned long location;
PASCAL: FUNCTION UltraPeekData(PPort : INTEGER;
Address : LONGINT) : BYTE;
Remarks: This routine is used to allow an application to look at any
location in UltraSound's DRAM. This can be handy for obtaining
VU information or any other time it is nice to know what is in
DRAM. Be aware that if the data is playable it will be in twos
compliment form. If the data that you want is 16 bit data, you
will need to peek both locations and do any appropriate
conversions. The data will be in low/high format. That means
that the low byte of the data will be in the even byte and the
high byte will be in the odd byte.
Returns: Data byte at location specified.
See also: UltraPokeData, UltraUpload
UltraPing
_________________________________
Purpose: To quickly check to see if an UltraSound is present at a
specified port.
C: int UltraPing(baseport);
int baseport;
PASCAL: FUNCTION UltraPing(PPort : WORD) : BOOLEAN;
Remarks: This routine will determine if an UltraSound is present by
attempting to read and write to its DRAM. This routine assumes
that at least a simple reset has been done since power-up so
that the board is no longer in a reset state. If it is on a
reset state, this routine will ALWAYS fail. UltraProbe pulls a
quick reset and then calls UltraPing.
Returns: C: ULTRA_OK if no problem.
NO_ULTRA if no board is found at specified I/O port.
PASCAL: TRUE if the card was found. FALSE otherwise.
If unsuccessful, check UltraErrorStr for the reason.
See also: UltraProbe
___________________________________________________________________________
62
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraPokeData
_________________________________
Purpose: To poke a byte into the UltraSound's DRAM.
C: void UltraPokeData(baseport,location,data);
unsigned int baseport;
unsigned long location;
unsigned char data;
PASCAL: PROCEDURE UltraPokeData(PPort : INTEGER;
Address : LONGINT;
Data : BYTE);
Remarks: Poke an 8 bit value directly into UltraSound DRAM. This can be
useful to set the value of the location that a voice is
pointing to. It is often desirable to point a voice to a known
value since its output is ALWAYS summed in to the output even
if the voice is not running. Be aware that there is no
automatic conversion of data poked into DRAM. Since the
UltraSound can only play twos compliment data, make sure that
the data you are poking is in that format. Also be careful
with 16 bit data.
See also: UltraPeekData, UltraDownload
___________________________________________________________________________
63
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraPrimeRecord
_________________________________
Purpose: To prime the record DMA channel for use.
C: int UltraPrimeRecord(pc_ptr,size,repeat);
void far *pc_ptr;
unsigned int size;
int repeat;
PASCAL: FUNCTION UltraPrimeRecord(PC_Ptr : POINTER;
Size : WORD;
RRepeat : BOOLEAN) : BOOLEAN;
Remarks: This routine will setup the DMA channel to do a record, but
does not start it. This can be used to help synchronize
events. Programming the DMA channel can take enough time so
that a few samples may be lost. (Depending on sample rate).
This routine will help alleviate this problem by doing the
programming ahead of time.
Returns: C: ULTRA_OK if no problem.
DMA_BUSY if DMA Channel is busy.
PASCAL: TRUE if setup was successful. FALSE otherwise.
If unsuccessful, check UltraErrorStr for the reason.
See also: UltraGoRecord
___________________________________________________________________________
64
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraPrimeVoice
_________________________________
Purpose: To prime a voice with values but NOT start it.
C: unsigned char UltraPrimeVoice(voice,begin,start,end,mode);
int voice;
unsigned long begin;
unsigned long start;
unsigned long end;
unsigned char mode;
PASCAL: FUNCTION UltraPrimeVoice(Voice : INTEGER;
VBegin : LONGINT;
VStart : LONGINT;
VEnd : LONGINT;
VMode : BYTE) : BYTE;
Remarks: This routine is used to do all the setup necessary to start a
voice but does NOT start it up. This can be useful if you want
to start more than 1 voice at the same time. Use
UltraPrimeVoice to do all the necessary setup and then use
UltraGoVoice to start the voices. UltraStartVoice calls
UltraPrimeVoice and then immediately UltraGoVoice.
Returns: An updated mode value. The mode may be modified on the basis
of the location parameters. This altered value should be the
one passed to UltraGoVoice.
See also: UltraStartVoice, UltraGoVoice
___________________________________________________________________________
65
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraProbe
_________________________________
Purpose: To probe for the existence of an UltraSound at a specified
port.
C: int UltraProbe(base_port);
unsigned int base_port;
PASCAL: FUNCTION UltraProbe(PPort : WORD) : BOOLEAN;
Remarks: This routine probes for the existence of an UltraSound card at
the specified base port. An application could call this before
calling UltraOpen to see if a card is present. UltraOpen calls
this routine also. The difference between UltraProbe and
UltraPing is that UltraProbe will pull a reset to make sure the
board is running. UltraPing assumes this has already been
done.
Returns: C: ULTRA_OK if no problem.
NO_ULTRA if no card was found at the port specified.
PASCAL: TRUE if the card is found. FALSE otherwise.
If unsuccessful, check UltraErrorStr for the reason.
See also: UltraOpen, UltraPing
___________________________________________________________________________
66
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraRampVolume
_________________________________
Purpose: To ramp a voice's volume up or down.
C: void UltraRampVolume(voice,start,end,rate,mode);
int voice;
unsigned int start;
unsigned int end;
unsigned char rate;
unsigned char mode;
PASCAL: PROCEDURE UltraRampVolume(Voice : INTEGER;
StartV : WORD;
EndV : WORD;
VRate : BYTE;
VMode : BYTE);
Remarks: Start a volume ramp from a starting volume to the ending
volume. The rate at which the ramp occurs can be calculated
using UltraCalcRate. The mode determines the looping and
interrupting characteristics of the ramp. If you choose to
have it interrupt at the end of the ramp, you should set up an
routine to call for a volume interrupt. This is done with the
routine UltraVolumeHandler. The volume mode bits are defined
in Appendix B.
See also: UltraCalcRate, UltraVolumeHandler
UltraReadRecordPosition
_________________________________
Purpose: To return the # of bytes recorded so far in a record.
C: unsigned int UltraReadRecordPosition(void);
PASCAL: FUNCTION UltraReadRecordPosition : WORD;
Remarks: This routine can be used to monitor the amount data recorded.
Returns: Number of BYTES recorded so far.
See also: UltraRecordData
___________________________________________________________________________
67
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraReadVoice
_________________________________
Purpose: To read a voice's current location.
C: unsigned long UltraReadVoice(voice);
int voice;
PASCAL: FUNCTION UltraReadVoice(Voice : INTEGER) : LONGINT;
Remarks: This routine can be used to monitor a voice's progress.
Returns: The voice's current position in DRAM.
See also: UltraSetVoice
UltraReadVolume
_________________________________
Purpose: To read a voice's current volume.
C: unsigned int UltraReadVolume(voice);
int voice;
PASCAL: FUNCTION UltraReadVolume(Voice : INTEGER) : WORD;
Remarks: This routine returns the current volume of a voice. This can
be useful when used in conjunction with volume ramps. The
value returned is logarithmic, not linear. PASCAL users can
use UltraReadLinearVolume.
Returns: 0-4095 value, the current logarithmic volume.
See also: UltraSetVolume, UltraRampVolume
___________________________________________________________________________
68
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraRecordData
_________________________________
Purpose: To record some data with the UltraSound from the active 'In'
ports.
C: int UltraRecordData(pc_ptr,control,size,wait,repeat);
void far *pc_ptr;
unsigned char control;
unsigned int size;
int wait;
int repeat;
PASCAL: FUNCTION UltraRecordData(PC_Ptr : POINTER;
Control : BYTE;
Size : WORD;
Wait : BOOLEAN;
RRepeat : BOOLEAN) : BOOLEAN;
Remarks: This routine will record a buffer of data from UltraSound. It
can be in either 8-bit mono or stereo. In stereo, there are
two bytes and the left byte is first. If mono is being used,
the left channel is the one that is sampled. See Appendix E
for the a description of the recording control bits. If 'wait'
is set to a non-zero value, then this routine will not return
until the buffer has been filled. If 'repeat' is TRUE, then
the DMA channel will be set up in auto-init mode so that the
recording is done indefinitely. If this is done, then the
buffer MUST reside completely in 1 64K page of PC RAM. Also,
it is probably necessary that your application hooks to the
record handler so that the control register on the UltraSound
can be hit to restart the recording process (UltraGoRecord).
This will be very quick since the PC DMA controller will not be
re-programmed.
Returns: C: ULTRA_OK if no problem.
DMA_BUSY if sampling DMA Channel is busy.
BAD_DMA_ADDR if autoinit buffer crosses 64k page.
PASCAL: TRUE if successful. FALSE otherwise.
If unsuccessful, check UltraErrorStr for the reason.
See also: UltraWaitRecordDMA, UltraSetRecordFrequency
UltraGoRecord
___________________________________________________________________________
69
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraRecordDMABusy
_________________________________
Purpose: To see if the record DMA channel is busy.
C: int UltraRecordDMABusy(void);
PASCAL: FUNCTION UltraRecordDMABusy : BOOLEAN;
Remarks: This routine checks to see if the record DMA channel is busy.
It might be busy doing a record (or playback if the record &
playback channels are the same).
Returns: C: 0 = Channel not Busy
2 = Channel Busy
PASCAL: TRUE if the channel is not available. FALSE if it is.
See also: UltraRecordData
UltraReset
_________________________________
Purpose: To reset the UltraSound.
C: int UltraReset(voices);
int voices;
PASCAL: FUNCTION UltraReset(Voices : INTEGER) : BOOLEAN;
Remarks: This routine is called by UltraOpen to make sure the card is in
a known state. UltraClose also calls this routine.
Returns: C: ULTRA_OK if no problem.
BAD_NUM_OF_VOICES if # of voices not in range.
PASCAL: TRUE if card is successfully reset.
If FALSE, check UltraErrorStr for the reason.
See also: UltraOpen, UltraClose
___________________________________________________________________________
70
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraSetBalance
_________________________________
Purpose: To set a voice's pan position.
C: void UltraSetBalance(voice,data);
int voice;
int data;
PASCAL: PROCEDURE UltraSetBalance(Voice : INTEGER;
Data : BYTE);
Remarks: This routine sets the voice's position between right and left
speakers. A 0 will place the audio all the way to the left
whereas a 15 will put the sound all the way to the right.
Values that are out of range will move the balance to the
nearest extreme.
UltraSetFrequency
_________________________________
Purpose: To set a voice's playback frequency.
C: void UltraSetFrequency(voice,speed_hz);
int voice;
unsigned long speed_hz;
PASCAL: PROCEDURE UltraSetFrequency(Voice : INTEGER;
Speed_Khz : LONGINT);
Remarks: This routine sets the voice's playback rate to the specified
absolute frequency. The number of active voices is taken into
account when making the appropriate calculations.
UltraSetLoopMode
_________________________________
Purpose: To set a voice's loop mode.
C: void UltraSetLoopMode(voice,mode);
int voice;
unsigned char mode;
PASCAL: PROCEDURE UltraSetLoopMode(Voice : INTEGER;
VMode : BYTE);
Remarks: This routine will set this voice's looping mode to the
specified mode. See Appendix C for the definition of these
bits.
___________________________________________________________________________
71
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraSetRecordFrequency
_________________________________
Purpose: To set the recording rate.
C: void UltraSetRecordFrequency(rate);
unsigned long rate;
PASCAL: PROCEDURE UltraSetRecordFrequency(Rate : LONGINT);
Remarks: This routine sets the record rate to the specified frequency.
Since the UltraSound uses the PC DMA channel to do the sampling
directly into PC RAM, no voice specification is necessary.
UltraSetVoice
_________________________________
Purpose: To set a voice to an absolute position in DRAM.
C: void UltraSetVoice(voice,location);
int voice;
unsigned long location;
PASCAL: PROCEDURE UltraSetVoice(Voice : INTEGER;
Location : LONGINT);
Remarks: This routine sets a voice's current position to an absolute
location. This can be useful to set a voice to a location with
a known value since all voices' current locations are summed in
to the output even if the voice is not running. 'Pops' in the
audio may result if a voice is set to a location that contains
a significant value.
UltraSetVoiceEnd
_________________________________
Purpose: To set a voice's end position.
C: void UltraSetVoiceEnd(voice,end);
int voice;
unsigned long end;
PASCAL: PROCEDURE UltraSetVoiceEnd(Voice : INTEGER;
VEnd : LONGINT);
Remarks: This routine sets a new endpoint for the specified voice. Used
in conjunction with UltraSetLoopMode to turn looping off, a
sampled decay can be implemented.
See also: UltraSetLoopMode
___________________________________________________________________________
72
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraSetVolume
_________________________________
Purpose: To set a voice's current logarithmic volume.
C: void UltraSetVolume(voice,volume);
int voice;
unsigned int volume;
PASCAL: PROCEDURE UltraSetVolume(Voice : INTEGER;
Volume : WORD);
Remarks: This routine sets the volume of the voice to a specific
logarithmic value. The range is from 0 to 4095. Use
UltraSetLinearVolume to do linear volumes.
See also: UltraSetLinearVolume
UltraSizeDRAM
_________________________________
Purpose: To Find the amount of DRAM available on the UltraSound.
C: int UltraSizeDram(void);
PASCAL: FUNCTION UltraSizeDRAM : INTEGER;
Note: This routine will always return the same value, which is
the amount of DRAM that has been installed on the card. Use
UltraMemAvail to see how much DRAM is still free.
Remarks: For C users, this routine could be used by an application to
determine how much it can load into the UltraSound.
UltraMemInit calls this to determine how much can be used for
its memory pool.
Returns: # of kilobytes found on the UltraSound.
See also: UltraMemInit
___________________________________________________________________________
73
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraStartTimer
_________________________________
Purpose: To set up and start either Timer 1 or Timer 2.
C: void UltraStartTimer(timer,duration);
int timer;
unsigned char duration;
PASCAL: PROCEDURE UltraStartTimer(Timer : INTEGER;
Duration : BYTE);
Remarks: This routine can be used to start up one of two available
hardware timers. Timer #1 is an 80 microsecond (.00008s)
timer. Timer #2 is a 320 microsecond (.00032s) timer. When
starting either timer, you supply the # of counts before the
timer 'ticks'. When the timer 'ticks', it ALWAYS calls the
callback routine defined for it. If you don't supply one, a
default is used.
These timers can be used to trigger various real time events.
They are used extensively in music compostition programs.
Please remember that the callback routine is called directly
from the interrupt handler, so you must be careful what you do
in the callback routine.
Note that the specified timer is automatically restarted after
it ticks. Your application must explicitly call UltraStopTimer
to shut it off.
See also: UltraStopTimer, UltraTimerStopped
UltraTimer1Handler, UltraTimer2Handler.
Example: Giving Timer 1 a duration of 10 counts would make the timer
tick every 800 microseconds (.0008s). This would mean your
callback routine is called 1250 times a second.
___________________________________________________________________________
74
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraStartVoice
_________________________________
Purpose: To set up and start a voice playing.
C: void UltraStartVoice(voice,begin,start,end,mode);
int voice;
unsigned long begin;
unsigned long start;
unsigned long end;
unsigned char mode;
PASCAL: PROCEDURE UltraStartVoice(Voice : INTEGER;
VBegin : LONGINT;
VStart : LONGINT;
VEnd : LONGINT;
VMode : BYTE);
Remarks: This routine will set up and start up a voice. The voice will
begin playback at the 'begin' and continue to 'end'. If
looping is enabled for this voice, then it will then jump to
'start' and then continue to 'end'. The method of looping is
determined by 'mode'. See Appendix C for the definition of
these bits.
See also: UltraSetVoiceEnd, UltraSetLoopMode
UltraStopTimer
_________________________________
Purpose: To stop a timer which has been previously activated.
C: void UltraStopTimer(timer);
int timer;
PASCAL: PROCEDURE UltraStopTimer(Timer : INTEGER);
Remarks: If you have started a timer with UltraStartTimer, you will
probably want to shut it off before shutting down your
application. If you forget, UltraClose automatically shuts it
down.
See also: UltraStartTimer
___________________________________________________________________________
75
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraStopVoice
_________________________________
Purpose: To stop a voice which is playing.
C: void UltraStopVoice(voice);
int voice;
PASCAL: PROCEDURE UltraStopVoice(Voice : INTEGER);
Remarks: This routine will stop a voice which is playing at it's current
position. Don't forget that if a voice is left at an unknown
position, the data that is at that position will still be
summed into the final output.
See also: UltraStartVoice, UltraSetVoiceEnd
UltraStopVolume
_________________________________
Purpose: To stop a currently active volume ramp.
C: void UltraStopVolume(voice);
int voice;
PASCAL: PROCEDURE UltraStopVolume(Voice : INTEGER);
Remarks: You can use this routine if you wish to stop an volume ramp
after a specified period of time, or you wish to make sure that
a volume ramp has stopped.
See also: UltraRampVolume, UltraRampLinearVolume
UltraTimerStopped
_________________________________
Purpose: To check to see if a timer is running.
C: int UltraTimerStopped(timer);
int timer;
PASCAL: FUNCTION UltraTimerStopped(Timer : INTEGER) : BOOLEAN;
Remarks: This routine can be used to see if a timer is currently being
used.
Returns: FALSE if still running, TRUE if stopped.
See also: UltraStartTimer, UltraStopTimer
___________________________________________________________________________
76
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraTrimJoystick
_________________________________
Purpose: To set the trim voltage on the joystick port.
C: void UltraTrimJoystick(value);
unsigned char value;
PASCAL: PROCEDURE UltraTrimJoystick(JoyVal : BYTE);
Remarks: This routine is used to set the speed compensation value on the
joystick port on the UltraSound. The faster the computer, the
smaller this value should be. This allows all software that
reads the joystick to return consistent joystick positions
regardless of the speed of the machine. This is normally not
needed and probably should never be used in your application.
The utility ULTRAJOY.EXE which is included with all UltraSound
stock software is used to set this value.
UltraUpload
_________________________________
Purpose: To transfer the contents of a block of DRAM to PC RAM.
C: int UltraUpload(dataptr,control,dram_loc,len,wait);
void *dataptr;
unsigned char control;
unsigned long dram_loc;
unsigned int len;
int wait;
PASCAL: FUNCTION UltraUpload(DataPtr : POINTER;
Control : BYTE;
DRAM_Loc : LONGINT;
Len : WORD;
Wait : BOOLEAN) : BOOLEAN;
Remarks: This routine will retrieve a chunk of data from the
UltraSound's DRAM. It will transfer 'len' # of bytes to
DataPtr (in PC) from DRAM_loc (in UltraSound). If 'Wait' is
TRUE, then it will wait until the transfer is complete. If
'Wait' is FALSE, it will return as soon as transfer is started.
See Appendix D for a definition of the control bits. They
specify the type of data being retrieved.
Returns: C: ULTRA_OK if no problem.
DMA_BUSY if DMA Channel is busy.
PASCAL: TRUE if transfer was successful. FALSE otherwise.
If unsuccessful, check UltraErrorStr for the reason.
See also: UltraDownload, UltraDRAMDMAWait
___________________________________________________________________________
77
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraVectorVolume
_________________________________
Purpose: To ramp a volume from it's current position to a new value.
C: void UltraVectorVolume(voice,end_idx,rate,mode);
int voice;
unsigned int end;
unsigned char rate;
unsigned char mode;
PASCAL: PROCEDURE UltraVectorVolume(Voice : INTEGER;
VEnd : WORD;
VRate : BYTE;
VMode : BYTE);
Remarks: This routine can be used to ramp from an unknown volume value
to a new value. It is useful if you are doing volume envelopes
and need to restart the attack/decay sequence at any time.
See also: UltraRampVolume, UltraStopVolume
UltraVersion
_________________________________
Purpose: To return the version of the SDK code being used.
C: void UltraVersion(major,minor);
int *major;
int *minor;
PASCAL: PROCEDURE UltraVersion(VAR Major : BYTE;
VAR Minor : BYTE);
Remarks: This routine can be useful to track the version of the SDK that
was used in compiling your source code.
Returns: Major (1 digit) and minor (2 digits) version of the unit.
See also: UltraVersionStr
___________________________________________________________________________
78
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraVersionStr
_________________________________
Purpose: To return the version of the SDK code being used in a string.
C: This function is not available.
PASCAL: FUNCTION UltraVersionStr : String;
Remarks: This routine can be useful to track the version of the SDK that
was used in compiling your source code.
Returns: Major and minor version of the unit, in string format.
See also: UltraVersion
UltraVoiceStopped
_________________________________
Purpose: To return whether a voice is playing.
C: int UltraVoiceStopped(voice);
int voice;
PASCAL: FUNCTION UltraVoiceStopped(Voice : INTEGER) : BOOLEAN;
Remarks: This routine can be used to see if a sample has finished
playing .
Returns: TRUE if the voice is stopped, FALSE otherwise.
UltraVolumeStopped
_________________________________
Purpose: To determine if a volume ramp is running for a particular
voice.
C: int UltraVolumeStopped(voice);
int voice;
PASCAL: FUNCTION UltraVolumeStopped(Voice : INTEGER) : BOOLEAN;
Remarks: This routine is used to determine the current state of the
volume of the voice. It can be used to see if a volume ramp is
still running.
Returns: TRUE if no volume ramp is running, FALSE otherwise.
See also: UltraRampVolume, UltraRampLinearVolume
___________________________________________________________________________
79
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraWaitDRAMDMA
_________________________________
Purpose: To wait for a DRAM DMA transfer to complete.
C: void UltraWaitDramDMA(void);
PASCAL: PROCEDURE UltraWaitDRAMDMA;
Remarks: If a DMA transfer to/from DRAM is started but told not to wait
for it to complete, this routine can be used to wait until it
has completed.
See also: UltraDownload, UltraUpload
UltraWaitRecordDMA
_________________________________
Purpose: To wait for a recording DMA transfer to complete.
C: void UltraWaitRecordDMA(void);
PASCAL: PROCEDURE UltraWaitRecordDMA;
Remarks: This can be used to let an application wait until a complete
sample is finished being acquired.
See also: UltraRecordData
___________________________________________________________________________
80
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraAllocVoice
_________________________________
Purpose: To allocate a new voice not currently being used.
C: int UltraAllocVoice(voice_num,new_num);
int voice_num;
int *new_num;
PASCAL: FUNCTION UltraAllocVoice(VAR Voice_Num : INTEGER) : BOOLEAN;
Remarks: This routine will return a voice for your application to use.
If you supply a voice number, it will attempt to allocate that
particular voice. If you pass a -1 for the voice number, it
will return the next free voice. This routine will only
allocate voices up to the # of active voices specified in the
UltraOpen function.
Returns: C: ULTRA_OK Got a voice ok
VOICE_NOT_FREE Can't get the voice or none left.
VOICE_OUT_OF_RANGE Specified voice out of range.
PASCAL: TRUE if there was no problem allocating the voice.
If FALSE, check UltraErrorStr for the reason.
See also: UltraClearVoices, UltraFreeVoices
UltraClearVoices
_________________________________
Purpose: To reset all voices to an un-allocated state.
C: void UltraClearVoices(void);
PASCAL: PROCEDURE UltraClearVoices;
Remarks: This routine will deallocate all previously allocated voices.
It would be advisable to call this before using either
UltraAllocVoice or UltraFreeVoice.
See also: UltraAllocVoice, UltraFreeVoice.
___________________________________________________________________________
81
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraFreeVoice
_________________________________
Purpose: To free up an allocated voice.
C: void UltraFreeVoice(voice_num);
int voice_num;
PASCAL: PROCEDURE UltraFreeVoice(Voice_Num : INTEGER);
Remarks: This routine will free up a previously allocated voice. This
should be used when your application no longer needs the voice
so it can be re-allocated at another time.
See also: UltraClearVoices, UltraAllocVoice.
UltraVoiceOff
_________________________________
Purpose: To allow flexibility in stopping a voice.
C: void UltraVoiceOff(voice,end);
int voice;
int end;
PASCAL: PROCEDURE UltraVoiceOff(Voice : INTEGER;
VEnd : BOOLEAN);
Remarks: This routine will either stop a voice immediately or let it
finish its current loop. If 'VEnd' is FALSE then it will stop
abruptly, otherwise it will finish the current loop.
UltraReadVoice could be called afterwards if you need to know
where the loop finished.
If used with UltraSetVoiceEnd, you could implement a sampled
decay on the end of your sample. This would occur if your loop
point was not at the end of your data, and you changed the end
point to the real end point of your data and then called this
routine with VEnd set to TRUE.
See also: UltraReadVoice, UltraSetVoiceEnd
___________________________________________________________________________
82
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraVoiceOn
_________________________________
Purpose: To turn a voice on at a given frequency.
C: void UltraVoiceOn(voice,begin,s_loop,e_loop,control,freq);
int voice;
unsigned long begin;
unsigned long s_loop;
unsigned long e_loop;
unsigned char control;
unsigned long freq;
PASCAL: PROCEDURE UltraVoiceOn(Voice : INTEGER;
VBegin : LONGINT;
Start_Loop : LONGINT;
End_Loop : LONGINT;
Control : BYTE;
Freq : LONGINT);
Remarks: This routine just sets the frequency with UltraSetFrequency and
then calls UltraStartVoice.
See also: UltraSetFrequency, UltraStartVoice
UltraSetLinearVolume
_________________________________
Purpose: To set a voice's volume to a linearized value.
C: void UltraSetLinearVolume(voice,index);
int voice;
int index;
PASCAL: PROCEDURE UltraSetLinearVolume(Voice : INTEGER;
Index : INTEGER);
Remarks: This routine indexes into a table to translate a linear volume
(0-511) to a logarithmic one (0-4095), and then calls
UltraSetVolume.
See also: UltraSetVolume
___________________________________________________________________________
83
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraReadLinearVolume
_________________________________
Purpose: To read a voice's volume as a linear value.
C: This function is not available.
PASCAL: FUNCTION UltraReadLinearVolume(Voice : INTEGER) : INTEGER;
Remarks: This routine indexes into a table to translate a 0-4095
logarithmic volume to a 0-511 linear volume.
Returns: Linear Volume Value (0-511).
See also: UltraSetVolume, UltraSetLinearVolume
UltraRampLinearVolume
_________________________________
Purpose: To ramp a voice's volume between linear volume values.
C: void UltraRampLinearVolume(voice,start,end,msecs,mode);
int voice;
unsigned int start;
unsigned int end;
unsigned long msecs;
unsigned char mode;
PASCAL: PROCEDURE UltraRampLinearVolume(Voice : INTEGER;
Start_Idx : WORD;
End_Idx : WORD;
Msecs : LONGINT;
VMode : BYTE);
Remarks: This routine is used to ramp between linear volume settings.
It uses the same method as UltraSetLinearVolume to determine
the actual volume settings to use, and then calls
UltraRampVolume.
See also: UltraRampVolume, UltraSetLinearVolume
___________________________________________________________________________
84
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraVectorLinearVolume
_________________________________
Purpose: To ramp a linear volume from it's current position to a known
end point.
C: void UltraVectorLinearVolume(voice,end,rate,mode)
int voice;
unsigned int end;
unsigned char rate;
unsigned char mode;
PASCAL: PROCEDURE UltraVectorLinearVolume(Voice : INTEGER;
End_Idx : WORD;
VRate : BYTE;
VMode : BYTE);
Remarks: This routine can be used to ramp from an unknown volume to a
new linear volume. It is useful if you are doing volume
envelopes and need to restart the attack/decay sequence at any
time. It can also produce a smoother ramp from one volume to
another, since arbitrarily setting a volume that is far away
from the current volume can cause 'pops'.
See also: UltraSetLinearVolume, UltraReadLinearVolume
___________________________________________________________________________
85
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Chapter 5 - Focal Point 3D Sound
5.0 Introduction
Three dimensional audio on the UltraSound is achieved by a technique called
binaural representation. Basically, this means that a mono sound is
'shaped' in such a way that when it is presented to the right and left ears
properly, the sound seems to come from the proper place in space. This
technique is also called convolution. This is done thru algorithms
developed by Focal Point(tm) 3D Audio. Focal Point has provided a utility
(called FP3D.EXE) to convert a mono sound file to a 3D file capable of
being played on an UltraSound. The basic concept is that the mono sound is
processed in such a way that the file that is output contains up to 6
tracks of sound. When the sound is played back, the volumes and balances
are adjusted to make the sound appear to originate from anywhere in the 3D
space. It is possible to create files that only have 4 tracks and can
therefore only be positioned in 2 dimensions. This may be adequate for
many applications and it will make the resultant file smaller.
There are 2 types of 3D sound that an application might want to use. The
first is a sound effect. This is a sound that can be completely loaded
into DRAM and played and positioned at any time. It is used for things
like gunshots, cars etc. These can be looped or non-looped. The other
type of sound is a sound track. This is for a very long sound that cannot
be loaded in DRAM all at once. The implementation of each of these methods
is very different. A sound effect is implemented using a blocked data
format. This means that each track's data is in a block of its own. A
sound track uses interleaved data. This means that all the track's data is
interleaved together. For example, a blocked file would look like this:
HEADER FFFFFRRRRRBBBBBLLLLLUUUUUDDDDD....
whereas an interleaved file would look like this:
HEADER FRBLUDFRBLUDFRBLUDFRBLUDFRBLUD...
where
F = Front Track L = Left Track
R = Right Track U = Up Track
B = Behind Track D = Down Track
Both of these methods have their individual advantages and disadvantages.
First, the interleaved method makes it very easy to read in the data in a
continuous stream since it will look the same all the way through the file.
It is also faster to read 60K of data once rather than 6 10K reads. This
makes it very useful for a sound track. However, one drawback is that it
has a very limited number of frequencies that it will run at. The reason
for this is rather difficult to explain, but it pertains to getting the
UltraSound's voices to play every 4th (or 5th, etc) sample. The UltraSound
normally would interpolate between data points but it can't do that here
because the adjacent data points are not in the same track.
___________________________________________________________________________
86
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
If you want to run at 22050 Hz, then you need to have only 28 active voices
to accomplish this. If you want to play a track at 44100 Hz, you must have
only 14 active voices. Blocked data doesn't have this problem. Since the
data is NOT interleaved, but in a block of contiguous DRAM, its frequency
can be adjusted to any value. This is usually very useful for sound
effects (rev'ing engines etc). Also, since the data is blocked, each
track's data can be allocated separately and can therefore be up to 256K.
An interleaved file must fit into 1 256K bank since we cannot play 16bit
data across a 256K bank. See the two example 3D programs provided (PLAY3D
and PLAY3DI) for ideas on how to implement 3D sound into you applications.
5.1 Creating 3D file
Please read the readme.3D file for information on creating a 3D file.
5.2 3D Sound Routines
UltraAbsPosition
_________________________________
Purpose: To place a sound using integer Cartesian coordinates.
C: void UltraAbsPosition3D(sound,xpos,ypos,zpos);
SOUND_3D *sound;
int xpos;
int ypos;
int zpos;
PASCAL: PROCEDURE UltraAbsPosition3D(VAR Sound : SOUND_3D;
XPos : INTEGER;
YPos : INTEGER;
ZPos : INTEGER);
Remarks: This routine will position a sound using standard cartesian
coordinates. The X position range is from -511 (left) to +511
(right). The Y position is from -511 (below) to +511 (above).
The Z position is from -511 (behind) to +511 (ahead). The X and
Z positions determine the azimuth position and Y determines the
elevation. The distance away from the listener is determined
using trigonometry. Once these are determined,
UltraAngPosition3D is called.
If the distance is calculated to be greater than 511, it is
clipped to 511. Also, if the distance is calculated to be 0, no
positioning is done since the origin is undefined. (i.e. A
sound cannot be generated INSIDE your head (origin)).
C users should be careful when using this routine, since the
trig functions will be needed from the C libraries.
See also: UltraAngPosition3D
___________________________________________________________________________
87
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraAngPosition3D
_________________________________
Purpose: To position a sound using integer polar coordinates.
C: void UltraAngPosition3D(sound,azimuth,elevation,volume);
SOUND_3D *sound;
int azimuth;
int elevation;
int volume;
PASCAL: PROCEDURE UltraAngPosition3D(VAR Sound : SOUND_3D;
AZIMuth : INTEGER;
Elevation : INTEGER;
Vol_Dist : INTEGER);
Remarks: This routine will position a 3D sound using polar coordinates.
The azimuth and elevation are specified in degrees. Azimuth is
the angle in the horizontal plane. Straight ahead is 0 degrees,
90 degrees is to the right, -90 degrees is to the left and 180
(or -180) is directly behind you. If an angle larger than 180
or smaller that -180 is specified, it is converted to its -180
to 180 equivalent. For example, 270 degrees is equivalent to -
90 degrees. Elevation is the angle of elevation above or below
the horizontal plane. 0 degrees is no elevation, 90 degrees is
straight up, and -90 is straight down. Any angle larger than 90
or smaller that -90 is ignored.
If more precision is needed, use UltraAngFltPosition3D so that
floating point arithmetic is used. Since that routine uses
floating point functions (slow), your application may not want
to use it.
See also: UltraAbsPosition3D
___________________________________________________________________________
88
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraAngFltPosition3D
_________________________________
Purpose: To position a sound using floating point polar coordinates.
C: void UltraAngFltPosition3D(sound,azimuth,elevation,volume);
SOUND_3D *sound;
double azimuth;
double elevation;
int volume;
PASCAL: PROCEDURE UltraAngFltPosition3D(VAR Sound : SOUND_3D;
AZIMuth : DOUBLE;
Elevation : DOUBLE;
Vol_Dist : INTEGER);
Remarks: This routine will position a 3D sound using polar coordinates.
The azimuth and elevation are specified as floating point
numbers in degrees. For example, 45 and one half degrees would
be specified as 45.5. Azimuth is the angle in the horizontal
plane. Straight ahead is 0 degrees, 90 degrees is to the right,
-90 degrees is to the left and 180 (or -180) is directly behind
you. If an angle larger than 180 or smaller that -180 is
specified, it is converted to its -180 to 180 equivalent. For
example, 270 degrees is equivalent to -90 degrees. Elevation is
the angle above or below the horizontal plane. 0 degrees is no
elevation, 90 degrees is straight up, and -90 is straight down.
Any angle larger than 90 or smaller that -90 is ignored.
If your application does not need to use the floating point
routine, it is advisable to use UltraAngPosition because it
avoids using some floating-point functions (which are slow).
UltraCloseDup3D
_________________________________
Purpose: To close a duplicated 3D sound effect.
C: void UltraCloseDup3D(sound);
SOUND_3D *sound;
PASCAL: PROCEDURE UltraCloseDup3D(VAR Sound : SOUND_3D);
Remarks: This routine must be used to free up the resources associated
with a duplicated 3D effect. This routine will only release the
voices used by the duplicated effect, not the DRAM allocated by
the original effect. The original effect should be closed with
UltraUnLoad3DEffect.
See also: UltraDup3D, UltraUnLoad3DEffect.
___________________________________________________________________________
89
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltrDup3D
_________________________________
Purpose: To copy a 3D sound effect.
C: int UltraDup3D(old,new);
SOUND_3D *old;
SOUND_3D *new;
PASCAL: FUNCTION UltraDup3D(VAR Current : SOUND_3D;
VAR Sound : SOUND_3D) : BOOLEAN;
Remarks: This routine is very useful if you want to use the same sound
effect in multiple places at once. This allows you to use the
same DRAM data and just allocate some more voices to move the
sound. This helps to save DRAM space. Make sure that you use
UltraCloseDup3D to free the voices, NOT UltraUnLoad3DEffect.
UltraUnLoad3DEffect will release all the DRAM for the sound.
This new effect can be passed to any other routines the same
way the original effect is.
Returns: C: ULTRA_OK No Error
NO_FREE_VOICES Not enough voices to make new handle
PASCAL: TRUE if duplication successful.
If FALSE, check UltraErrorStr for the reason.
See also: UltraCloseDup3D
___________________________________________________________________________
90
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraLoad3DEffect
_________________________________
Purpose: To load a 3D effect from the disk into DRAM.
C: int UltraLoad3DEffect(sound,filename,pc_buffer,size);
SOUND_3D *sound;
char *filename;
void far *pc_buffer;
unsigned int size;
PASCAL: FUNCTION UltraLoad3DEffect(VAR Sound : SOUND_3D;
VAR FileName : STRING;
PC_Buffer : POINTER;
Size : WORD) : BOOLEAN;
Remarks: This routine is used to load a 3D sound into the DRAM on the
UltraSound. It will allocate all necessary resources so that
UltraStart3D can be called later. As many buffers of DRAM as
needed will be allocated along with the proper number of
voices. These resources will be freed up when you call
UltraUnLoad3DEffect. The file specified MUST be a properly
formatted or the routine will fail. This means that it must
have the proper header and 3D data in it. The 'pc_buffer' is a
buffer supplied by your application for this routine's use to
download data into the UltraSound. The 'size' parameter is the
size of the 'pc_buffer'. The larger this buffer is, the faster
it will download.
Returns: C: ULTRA_OK No error
NO_3D_FILE 3D file not found
BAD_3D_HDR 3D header is bad
NO_3D_HDR File doesn't have a valid header
NOT_BLOCK_DATA File is not in blocked format
NO_FREE_VOICES Not enough free voices
BAD_FILE_DATA Not enough data or bad file
CORRUPT_MEM Memory structs have been corrupted
DMA_BUSY DMA channel busy
PASCAL: TRUE if the file could be loaded.
If FALSE check UltraErrorStr for the reason.
See also: UltraMemAlloc, UltraVoiceAlloc, UltraDownload
___________________________________________________________________________
91
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraSetFreq3D
_________________________________
Purpose: To set the frequency of a 3D sound effect.
C: void UltraSetFreq3D(sound,frequency);
SOUND_3D *sound;
unsigned long frequency;
PASCAL: FUNCTION UltraSetFreq3D(VAR Sound : SOUND_3D;
Frequency : LONGINT) : BOOLEAN;
Remarks: This routine will allow you to alter the frequency that the 3D
sound is using. This allows you to do pitch shifting to get a
doppler shift type effect. This routine can only be done on
blocked data.
Returns: C: ULTRA_OK No problem
NOT_BLOCKED_DATA Can't change freq of interleaved data
PASCAL: TRUE if the frequency was changed ok.
If FALSE, check UltraErrorStr for the reason.
UltraRelease3DInterleave
_________________________________
Purpose: To release 3D resources for an interleaved effect.
C: void UltraRelease3DInterleave(sound)
SOUND_3D *sound;
PASCAL: PROCEDURE UltraRelease3DInterleave(VAR Sound : SOUND_3D);
Remarks: This routines will release the DRAM and voices allocated for an
interleaved sound track.
See also: UltraSetup3DInterleave
___________________________________________________________________________
92
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraSetup3DInterleave
_________________________________
Purpose: To set up for an interleaved 3D sound effect.
C: int UltraSetup3DInterleave(sound,filename,size);
SOUND_3D *sound;
char *filename;
unsigned long size;
PASCAL: FUNCTION UltraSetup3DInterleave(VAR Sound : SOUND_3D;
VAR FileName : STRING;
Size : LONGINT) : BOOLEAN;
Remarks: This routine will allocate the voices and memory necessary to
play back an interleaved 3D sound. It will NOT load any of the
file data into DRAM. Your application is responsible for that.
It will open the file, read the header, allocate the
appropriate resources, and set up the begin, start and end loop
points for each voice. Since the sound is interleaved, the
loop points are staggared appropriately.
Returns: C: ULTRA_OK No error
NO_3D_FILE 3D file not found
BAD_3D_HDR 3D header is bad
NO_3D_HDR File doesn't have a valid header
NOT_INTERLEAVED_DATA File in blocked format
NO_FREE_VOICES Not enough free voices
BAD_FILE_DATA Not enough data or bad file
CORRUPT_MEM Memory structs have been corrupted
PASCAL: TRUE if the file could be read successfully.
If FALSE, check UltraErrorStr for the reason.
See also: UltraLoad3DEffect
UltraStart3D
_________________________________
Purpose: To start a 3D sound which has been loaded.
C: void UltraStart3D(sound);
SOUND_3D *sound;
PASCAL: PROCEDURE UltraStart3D(VAR Sound : SOUND_3D);
Remarks: This routine will start a 3D sound. If you want it to begin at
a specific point in space, be sure that you position it first.
It is not necessary to stop the sound before starting it again.
See also: UltraStart3D
___________________________________________________________________________
93
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
UltraStop3D
_________________________________
Purpose: To stop a 3D sound which is playing.
C: void UltraStop3D(sound,abruptly);
SOUND_3D *sound;
int abruptly;
PASCAL: PROCEDURE UltraStop3D(VAR Sound : SOUND_3D;
Abruptly : BOOLEAN);
Remarks: This routine will stop a 3D sound. There are two ways to stop a
sound: if the 'abruptly' flag is TRUE, then the sound will shut
off immediately; if it is FALSE, then the sound will be ramped
down very quickly. The second method will give a smoother
transition.
UltraUnLoad3DEffect
_________________________________
Purpose: To free resources used by a 3D effect.
C: void UltraUnLoad3DEffect(sound);
SOUND_3D *sound;
PASCAL: PROCEDURE UltraUnLoad3DEffect(VAR Sound : SOUND_3D);
Remarks: This routine is used to free up all the resources (voices &
DRAM) that a 3D sound uses. Since a 3D sound can use a lot
of the voices & DRAM, you should free up the resources
whenever you can.
See also: UltraLoad3DEffect
___________________________________________________________________________
94
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Appendix A - Error Codes
======
C:
======
Main routines: (these are defined in ULTRAERR.H)
ULTRA_OK 1 No error
BAD_NUM_OF_VOICES 2 must be 14-32
NO_MEMORY 3 Not enough free DRAM left
CORRUPT_MEM 4 memory structures are corrupt
NO_ULTRA 5 Can't find an UltraSound
DMA_BUSY 6 This DMA channel is still busy
BAD_DMA_ADDR 7 auto init across page boundaries
VOICE_OUT_OF_RANGE 8 allocate a voice past # active
VOICE_NOT_FREE 9 voice has already been allocated
NO_FREE_VOICES 10 not any voices free
3D functions: (these are defined in THREED.H)
NO_3D_FILE 101 Can't open file
BAD_3D_HDR 102 Header for file is corrupt/non-existent
NO_DRAM_3D 103 Not enough room for this sound
NO_3D_HDR 104 No header on this file
NOT_BLOCK_DATA 105 data not in block format
BAD_FILE_DATA 106 not enough data as header says
NOT_INTERLEAVED_DATA 107 data not in interleaved format
BAD_3D_FREQ 108 invalid freq. for interleaved 3D data
=========
PASCAL:
=========
Please see the discussion of the PASCAL error handling techniques at the
end of section 1.8.1.
___________________________________________________________________________
95
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Appendix B - Volume Control
Here are the volume ramp control bit definitions:
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Reserved
| | | | | | +-------- Reserved
| | | | | +------------ Reserved
| | | | +---------------- loop enable (0=no loop, 1=loop)
| | | +-------------------- bi-direction. loop (1=enable)
| | +------------------------ Enable volume ramp IRQ
| +---------------------------- Reserved
+-------------------------------- Reserved
The bits that should be set by the application to get a particular type of
volume ramp. The completed value should be supplied to UltraRampVolume and
UltraRampLinearVolume. If volume interrupts are enabled, make sure that you
have set up a volume interrupt handler (see UltraVolumeHandler). This can
be used to create your own multi-point volume envelopes.
Bi-directional looping can be used to create a tremelo effect.
___________________________________________________________________________
96
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Appendix C - Voice Control
Here are the voice control bit definitions:
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Rollover when hit ending addr
| | | | | | +-------- Reserved
| | | | | +------------ data type (0=8 bit 1=16 bit)
| | | | +---------------- loop enable (0=no loop, 1=loop)
| | | +-------------------- bi-direction. loop (1=enable)
| | +------------------------ Enable wavetable IRQ
| +---------------------------- Direction (0=inc, 1=dec)
+-------------------------------- Reserved
The UltraSound is capable of playing back 8 or 16 bit data. (It can only
record 8 bit). Stereo is handled by using 2 voices. It can loop on the data
in either a uni-directional or bi-directional mode. If you have asked that
a particular voice generate a wavetable interrupt when it hits the end of
the data (or loop point, if looping is specified), be sure you have
specified a wavetable interrupt hander (UltraWaveHander). The mode bits
would be constructed and passed to UltraStartVoice and UltraSetLoopMode.
The rollover bit is used to tell the software to program the hardware:
generate an interrupt when the voice hits the end address, but don't stop
playing the voice (or loop if looping is enabled). This allows a voice to
continue to play but gives the software a 'marker point' in the playback.
This can be very powerfull to allow a seamless playback. The hardware bit
for turning rollover on is acutally in the voice's volume control register
(there were no spare bits in the voice control register). One of the bits
is shared to tell the toolkit software to enable the rollover in the volume
control register.
___________________________________________________________________________
97
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Appendix D - DMA Control
Here are the dma to/from DRAM control bit definitions:
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Reserved
| | | | | | +-------- 0=write,1=Read
| | | | | +------------ Reserved
| | | | +---------------- Reserved
| | | +-------------------- Reserved
| | +------------------------ Reserved
| +---------------------------- Data size (0=8 bit, 1=16 bit)
+-------------------------------- (1=convert to 2's comp.)
Note: The UltraSound DRAM location MUST be on a 32 byte boundary.
UltraMemAlloc enforces this stipulation.
You define the byte to be passed to UltraUpload and UltraDownload using
these bits. To DMA the data out of DRAM, use UltraUpload. To send data to
the DRAM, use UltraDownload. Be sure to specify the sample size and whether
or not the data is in two's compliment form. The UltraSound can only play
data back that is in two's compliment form. If your sample is in one's
compliment form, turn on bit 7 when specifying the mode when you call
UltraDownload - the data will be translated to two's compliment as it is
being DMA'ed.
Note: If you are poking data into DRAM, you MUST put the data in twos
compliment yourself. This is accomplished by exclusive or-ing the
high bit with a 1.
___________________________________________________________________________
98
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Appendix E - Recording Control
Here are the recording control bit definitions:
=================================
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
=================================
| | | | | | | |
| | | | | | | +---- Reserved
| | | | | | +-------- mode (0=mono,1=stereo)
| | | | | +------------ Reserved
| | | | +---------------- Reserved
| | | +-------------------- Reserved
| | +------------------------ Reserved
| +---------------------------- Reserved
+-------------------------------- (1=Convert to 2's comp.)
___________________________________________________________________________
99
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Appendix F - Patch Files
This appendix contains information about the the patch file format. It
assumes the reader is familiar with wave table synthesis, music, sound,
and the GF1 ASIC chip that is the heart of the UltraSound audio card.
The UltraSound patch file is a collection of data structures and sound data
in the following format:
patch header (# instruments)
instrument header 1 (#layers)
layer 1 header (# waves)
wave 1 header
wave 1 data
wave 2 header
wave 2 data
...
wave n header
wave n data
layer 2 header (# waves)
wave 1 header
wave 1 data
wave 2 header
wave 2 data
...
wave n header
wave n data
instrument header 2 (#layers)
etc.
All of the Advanced Gravis UltraSound patches contain one instrument at the
current time. Except for the main patch header, each of the headers has a
size field which can be used to seek past unwanted data. For example, if a
patch has two instruments and you want to skip the first instrument, you
would read the first instrument header, and then skip INSTRUMENT_SIZE
bytes. What follows is the patch header definitions given in C and Pascal.
After the definitions, a field-by-field breakdown of the headers is given.
======
C:
======
#define ENVELOPES 6
#define HEADER_SIZE 12
#define ID_SIZE 10
#define DESC_SIZE 60
#define RESERVED_SIZE 40
#define PATCH_HEADER_RESERVED_SIZE 36
#define LAYER_RESERVED_SIZE 40
#define PATCH_DATA_RESERVED_SIZE 36
#define GF1_HEADER_TEXT "GF1PATCH110"
#define MAX_LAYERS 4
#define INST_NAME_SIZE 16
___________________________________________________________________________
100
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
typedef struct
{
char header[ HEADER_SIZE ];
char gravis_id[ ID_SIZE ]; /* Id = "ID#000002" */
char description[ DESC_SIZE ];
unsigned char instruments;
char voices;
char channels;
unsigned int wave_forms;
unsigned int master_volume;
unsigned long data_size;
char reserved[ PATCH_HEADER_RESERVED_SIZE ];
} PATCHHEADER;
typedef struct
{
unsigned int instrument;
char instrument_name[ 16 ];
long instrument_size;
char layers;
char reserved[ RESERVED_SIZE ];
} INSTRUMENTDATA;
typedef struct
{
char layer_duplicate;
char layer;
long layer_size;
char samples;
char reserved[ LAYER_RESERVED_SIZE ];
} LAYERDATA;
... continued on the next page ...
___________________________________________________________________________
101
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
typedef struct
{
char wave_name[7];
unsigned char fractions;
long wave_size;
long start_loop;
long end_loop;
unsigned int sample_rate;
long low_frequency;
long high_frequency;
long root_frequency;
int tune;
unsigned char balance;
unsigned char envelope_rate[ ENVELOPES ];
unsigned char envelope_offset[ ENVELOPES ];
unsigned char tremolo_sweep;
unsigned char tremolo_rate;
unsigned char tremolo_depth;
unsigned char vibrato_sweep;
unsigned char vibrato_rate;
unsigned char vibrato_depth;
/* bit 0 = 8 or 16 bit wave data. */
/* bit 1 = Signed - Unsigned data. */
/* bit 2 = looping enabled-1. */
/* bit 3 = Set is bidirectional looping. */
/* bit 4 = Set is looping backward. */
/* bit 5 = Turn sustaining on. (Env. pts. 3)*/
/* bit 6 = Enable envelopes - 1 */
char modes;
int scale_frequency;
unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */
char reserved[ PATCH_DATA_RESERVED_SIZE ];
} PATCHDATA;
...end of the C section. Please see the next page for the PASCAL
section...
___________________________________________________________________________
102
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
=========
PASCAL:
=========
CONST
ENVELOPES = 6;
HEADER_SIZE = 12;
ID_SIZE = 10;
DESC_SIZE = 60;
RESERVED_SIZE = 40;
PATCH_HEADER_RESERVED_SIZE = 36;
LAYER_RESERVED_SIZE = 40;
PATCH_DATA_RESERVED_SIZE = 36;
GF1_HEADER_TEXT : ARRAY[1..12] OF CHAR = 'GF1PATCH110';
TYPE
PATCHHEADER = RECORD
Header : ARRAY[1..HEADER_SIZE] OF CHAR;
Gravis_ID : ARRAY[1..ID_SIZE] OF CHAR; { Id = 'ID#000002' }
Description : ARRAY[1..DESC_SIZE] OF CHAR;
Instruments : SHORTINT;
Voices : SHORTINT;
Channels : SHORTINT;
Wave_Forms : WORD;
Master_Volume : WORD;
Data_Size : LONGINT;
Reserved : ARRAY[1..PATCH_HEADER_RESERVED_SIZE] OF BYTE;
END;
INSTRUMENTDATA = RECORD
Instrument : WORD;
Instrument_Name : ARRAY[1..16] OF CHAR;
Instrument_Size : LONGINT;
Layers : SHORTINT;
Reserved : ARRAY[1..RESERVED_SIZE] OF BYTE;
END;
LAYERDATA = RECORD
Layer_Duplicate : SHORTINT;
Layer : SHORTINT;
Layer_Size : LONGINT;
Samples : SHORTINT;
Reserved : ARRAY[1..RESERVED_SIZE] OF BYTE;
END;
...continued on the next page...
___________________________________________________________________________
103
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
PATCHDATA = RECORD
Wave_Name : ARRAY[1..7] OF CHAR;
Fractions : BYTE;
Wave_Size : LONGINT;
Start_Loop : LONGINT;
End_Loop : LONGINT;
Sample_Rate : WORD;
Low_Frequency : LONGINT;
High_Frequency : LONGINT;
Root_Frequency : LONGINT;
Tune : INTEGER;
Balance : BYTE;
Envelope_Rate : ARRAY[1..ENVELOPES] OF BYTE;
Envelope_Offset : ARRAY[1..ENVELOPES] OF BYTE;
Tremolo_Sweep : BYTE;
Tremolo_Rate : BYTE;
Tremolo_Depth : BYTE;
Vibrato_Sweep : BYTE;
Vibrato_Rate : BYTE;
Vibrato_Depth : BYTE;
{ bit 0 = 8 or 16 bit wave data. }
{ bit 1 = Signed - Unsigned data. }
{ bit 2 = looping enabled-1. }
{ bit 3 = Set is bidirectional looping. }
{ bit 4 = Set is looping backward. }
{ bit 5 = Turn sustaining on. (Env. pts. 3) }
{ bit 6 = Enable envelopes - 1 }
Modes : SHORTINT;
Scale_Frequency : INTEGER;
Scale_Factor : WORD; { From 0 to 2048 or 0 to 2 }
Reserved : ARRAY[1..PATCH_DATA_RESERVED_SIZE] OF BYTE;
END;
File Header
_________________________________
'Header'
The header field should contain the text "GF1PATCH110." The first 8
bytes will always be GF1PATCH. The next three bytes are the version
number of the patch format. As fields are added to the patch, the
number will be incremented. All of the UltraSound patches are
currently at version 110. The older 100 patches are obsolete and
should no longer be in use.
'Description'
This description field is usually for copyright information.
'Instruments'
The number of instruments in the patch. All of the gravis patches
contain only one instrument.
___________________________________________________________________________
104
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
'Voices'
The GF1 synth can update 14 voices at 44.1Khz. As the number of
voices increases, the actual output rate of each voice drops. This
field should contain the number of voices that were used when creating
the patch. This field could be used by a MIDI engine to try and make
the patch sound the same regardless of the number of active voices.
Currently this feature is not implemented in the gravis MIDI engine.
'Channels'
This field is unused. Only mono data can be played out a voice with
the GF1.
'Wave_Forms'
The total number of waveforms in the patch. This field is used by
programs which need to preallocate space for wave form headers before
the patch is loaded.
'Master_Volume'
This field is currently unused.
'Data_Size'
The size of the patch data after it is loaded into GF1 dram. This
number includes the space needed to align each of the waveforms on 32
byte boundaries. If you patch loader maintains linked list of
waveforms in dram, and you need to use an extra 32 bytes per waveform,
then you can use the wave_forms field to figure out how much memory
you will need to load the patch. i.e. data_size + (32 * wave_forms).
Instrument Header
_________________________________
'Instrument'
This field is currently unused.
'Instrument_Name'
This field is currently unused.
'Instrument_Size'
The size of the instrument. The number of bytes to skip in order to
read the next instrument header.
'Layers'
The number of layers in this instrument. Multiple layers are usually
used in patches where more than one sound is required with a single
MIDI event (note on). For example, a piano would could have two
layers. The first would be the actual tone from the hammer hitting the
strings, and the second would be the (thunk) of the key being struck
and all of the mechanisms moving inside the piano. The mechanisms
would probably be frequency independant, and also independant of the
length of the tone.
___________________________________________________________________________
105
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Layer Header
__________________________
'Layer_Duplicate'
Currently unused. If the layer duplicate is nonzero, then this layer
should use the data from the previous layer. Only the headers will
follow.
'Layer'
The current layer number for this instrument
'Layer_Size'
The size of this layer. Can be used to seek past this layer in the
file.
'Samples'
The number of waveforms in this layer. This field is ignored if
layer_duplicate is true.
Wave Header
_________________________________
'Wave_Name'
This field is currently unused
'Fractions'
The start_loop and end_loop are the integer portions of the wavetable
address. The GF1 can interpolate between sample points and therefore
meore resolution than just the integer address is needed. The most
significant four bits are the fractional address for the start_loop,
and the least significant four bits are the fractional address for the
end_loop.
'Wave_Size'
The number of bytes of wave table data that follows -- not # of
samples.
'Start_Loop'
The integer portion of the starting loop address relative to the
beginning of the wave. This address is the relative number of bytes,
and not the number of samples.
'End_Loop'
The integer portion of the ending loop address relative to the
beginning of the wave. This address is the relative number of bytes,
and not the number of samples.
'Sample_Rate'
This is the sample rate of the recorded data. This number is not
related to the actual pitch of the recorded tone.
___________________________________________________________________________
106
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
'Low_Frequency'
Each wave covers a specific frequency range. This is the lowest
frequency that this wave can be used to play. This field is scaled be
1000 for accuracy.
'High_Frequency'
Each wave covers a specific frequency range. This is the highest
frequency that this wave can be used to play. This field is scaled by
1000 for accuracy. If there is another wave adjacent to this one and
its range overlaps this range, then the next waveform will always be
chosen.
'Root_Frequency'
If this wave is played back at the original sample_rate, then this
number should be the pitch of the original tone. This field is
modified to tune the wave to a particular pitch. This field is scaled
by 1000 for accuracy.
'Tune'
This field is unused. Tuning is accomplished by modifying the root
frequency.
'Balance'
0 is 100% to the right, and 15 is 100% to the left. As the balance is
shifted from left to right, the total output power of both channels is
constant.
'Envelope_Rate'
An array of 6 rates to implement a 6-point envelope. The first three
rates can be used for attack and decay. If the sustain flag is set,
than the third envelope point will be the sustain point. The last
three envelope points are for the release, and an optional "echo"
effect. If the last envelope point is left at an audible level, then
a sampled release can heard after the last envelope point. The rate
values are sent directly to the GF1 hardware, and are described in the
volume ramping section.
'Envelope_Offset'
An array of 6 offsets to implement a 6-point envelope. The first three
offsets can be used for attack and decay. If the sustain flag is set,
than the third envelope point will be the sustain point. The last
three envelope points are for the release, and an optional "echo"
effect. If the last envelope point is left at an audible level, then
a sampled release can heard after the last envelope point. The offset
values are sent directly to the GF1 hardware, and are described in the
volume ramping section.
'Tremolo_Sweep'
Not implemented. Tremolo starts automatically when the note sustains.
This will be changed in future software to gradually sweep in the
tremolo depth from 0 at the rate of tremolo_sweep / 45 seconds.
___________________________________________________________________________
107
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
'Tremolo_Rate'
The rate of amplitude modulation. 0 is 0.05 Hz, and 255 is 6 Hz. A
complete table is listed below.
'Tremolo_Depth'
0 means turn tremolo off. 255 provides a 16 dB modulation. A
complete table is listed below.
'Vibrato_Sweep'
Gradually sweep in the vibrato depth from 0 at the rate of
vibrato_sweep / 45 seconds.
'Vibrato_Rate'
The rate of frequency modulation. 0 is 0.05 Hz, and 255 is 6 Hz.
'Vibrato_Depth'
0 means turn vibrato off. 255 is a one octave modulation.
'Modes'
A set of bit fields describing modes and data type:
BIT 0- 16 bit data
BIT 1- unsigned data
BIT 2- looping enabled
BIT 3- bidirectional loop
BIT 4- play patch backwards. start at end address, loop backwards,
and then end at beginning address.
BIT 5- sustain - enveloping stops at third envelope point. a note
off will continue enveloping.
BIT 6- currently means enveloping enabled. All gravis patches have
this bit set. This field will be modified in the near future
to implement a sampled release at note off instead of at the
last envelope point. If this bit is on, the sample release
occurs after the last envelope point. If this bit is off, the
sampled release occurs at the note off.
BIT 7- fast release. The last three envelope points are ignored.
'Scale_Frequency'
Keyboard frequency scaling. Normally, MIDI note 64 plays a middle C.
A 65 plays a C#. frequency scaling changes the distance in pitch of
each MIDI note. The scale_frequency is the MIDI note number which is
the pivot point for scaling. If scale_frequency is 64, then MIDI note
64 will sound like a C4 regardless of scale factor.
'Scale_Factor'
1024 means normal scaling. Each MIDI note is one semitone away from
its neighbor. 512 would be 1/2 semitone apart. 2048 is two semitones
apart.
___________________________________________________________________________
108
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
Appendix G - 3D File Header
Here is a definition for the data found in Focal-Point 3D files. All .F3D
files will have this format. Both C and PASCAL versions of the definition
are listed below.
======
C:
======
/* Bit definitions for tracks that are in a 3D file ... */
#define FRONT_TRACK 0x01
#define RIGHT_TRACK 0x02
#define REAR_TRACK 0x04
#define LEFT_TRACK 0x08
#define ABOVE_TRACK 0x10
#define BELOW_TRACK 0x20
#define FBLOCK_3D 0x01 /* File data is blocked */
#define F16BIT_3D 0x02 /* 16 bit data */
#define FTWOS_CMP_3D 0x04 /* sound is in twos complement form */
#define FLOOPED_3D 0x08 /* sound is looped , not one shot*/
#define FBI_LOOP_3D 0x10 /* sound is bi-directional */
#define F3D_TYPE 0x60 /* Type of 3D sound */
/* types (F3D_TYPE) of 3D sound (only binaural currently supported) */
#define F_BINAURAL 0x20 /* Binaural representation */
#define F_SURROUND 0x40 /* Surround sound (???) */
#define F_QSOUND 0x60 /* Q sound (???) */
/* the following structure is exactly 256 bytes long ... */
typedef struct {
char id[10]; /* 3D FILE tag */
int major; /* major version # */
int minor; /* minor version # */
char description[80];
unsigned int type; /* See above .... */
int tracks; /* tracks included in this file ... */
int reserve1[24]; /* for expansion */
int maxvol; /* volume can range from 0 to maxvol */
int reserve2[10]; /* for expansion */
unsigned long blocksize; /* # of bytes in block data */
unsigned long loop_offset; /* byte offset to where loop begins */
unsigned long reserve3[9]; /* for expansion */
unsigned long frequency; /* initial playback frequency */
unsigned long reserve4[10]; /* for expansion */
} FILEHDR_3D;
...end of the C section. Please see the next page for the PASCAL
section...
___________________________________________________________________________
109
Ultrasound Software Development Kit (SDK) Version 2.10
___________________________________________________________________________
========
PASCAL
========
CONST
{ Bit definitions FOR tracks that are in a 3D FILE ... }
FRONT_TRACK = $01;
RIGHT_TRACK = $02;
REAR_TRACK = $04;
LEFT_TRACK = $08;
ABOVE_TRACK = $10;
BELOW_TRACK = $20;
FBLOCK_3D = $01; { FILE data is blocked, NOT interleaved }
F16BIT_3D = $02; { 16 bit data }
FTWOS_CMP_3D = $04; { sound is in twos complement form }
FLOOPED_3D = $08; { sound is looped , NOT one shot }
FBI_LOOP_3D = $10; { sound is bi-directional }
F3D_TYPE = $60; { TYPE OF 3D sound }
{ types (F3D_TYPE) OF 3D sound (only binaural currently supported) }
F_BINAURAL = $20; { Binaural representation }
F_SURROUND = $40; { Surround sound (???) }
F_QSOUND = $60; { Q sound (???) }
TYPE
FILEHDR_3D = RECORD
ID : ARRAY[0..9] OF CHAR; { 3D FILE tag }
Major : INTEGER; { Major version # }
Minor : INTEGER; { Minor version # }
Description : ARRAY[0..79] OF CHAR;
SType : WORD; { See above }
Tracks : INTEGER; { Tracks included }
Reserve1 : ARRAY[0..23] OF INTEGER; { for expansion }
MaxVol : INTEGER; { volume range 0-maxvol }
Reserve2 : ARRAY[0..9] OF INTEGER; { for expansion }
BlockSize : LONGINT; { # of bytes in block data }
Loop_Offset : LONGINT; { byte offset of loop begin}
Reserve3 : ARRAY[0..8] OF LONGINT; { for expansion }
Frequency : LONGINT; { playback frequency }
Reserve4 : ARRAY[0..9] OF LONGINT; { for expansion }
END;
{ the file header is exactly 256 bytes long }
___________________________________________________________________________
110